The unified package is fully typed. To ensure type safety, especially when working with different syntax trees (like hast, mdast, or nlcst), you should use the Plugin type with its generics.
Common patterns for typing plugins include:
- Plugins with options: Use
Plugin<[(Options | null | undefined)?]>. - Plugins working on a specific tree: Use
Plugin<[], TreeType>. - Plugins transforming one tree to another: Use
Plugin<[], SourceTreeType, TargetTreeType>. - Parser plugins: Use
Plugin<[], string, TreeType>. - Compiler plugins: Use
Plugin<[], TreeType, string>.
It is highly recommended to use the official node types for the syntax trees provided by related packages (e.g., @types/hast, @types/mdast, @types/nlcst).
/**
* @import {Root as HastRoot} from 'hast'
* @import {Root as MdastRoot} from 'mdast'
* @import {Plugin} from 'unified'
*/
/**
* @typedef Options
* Configuration (optional).
* @property {boolean | null | undefined} [someField]
* Some option (optional).
*/
// To type options:
/** @type {Plugin<[(Options | null | undefined)?]>} */
export function myPluginAcceptingOptions(options) {
const settings = options || {}
// `settings` is now `Options`.
}
// To type a plugin that works on a certain tree, without options:
/** @type {Plugin<[], MdastRoot>} */
export function myRemarkPlugin() {
return function (tree, file) {
// `tree` is `MdastRoot`.
}
}
// To type a plugin that transforms one tree into another:
/** @type {Plugin<[], MdastRoot, HastRoot>} */
export function remarkRehype() {
return function (tree) {
// `tree` is `MdastRoot`.
// Result must be `HastRoot`.
}
}
// To type a plugin that defines a parser:
/** @type {Plugin<[], string, MdastRoot>} */
export function remarkParse(options) {}
// To type a plugin that defines a compiler:
/** @type {Plugin<[], HastRoot, string>} */
export function rehypeStringify(options) {}