1

(来自@type/markdown-it 的类型) https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/markdown-it/lib/index.d.ts#L93

我想为方法的可能参数创建参数类型,该markdown-it use方法的类型如下:

type PluginSimple = (md: MarkdownIt) => void;
type PluginWithOptions<T = any> = (md: MarkdownIt, options?: T) => void;
type PluginWithParams = (md: MarkdownIt, ...params: any[]) => void;

我有一个反应钩子,我想提交这样的 markdown-it 插件:

type Plugin = MarkdownIt.PluginSimple |
  [MarkdownIt.PluginWithOptions, {}?] | 
  [MarkdownIt.PLuginWithParams, ...any[]]
type Plugins = Plugin[]

function useMarkdown(source: any, plugins?: Plugins) {
  React.useEffect(() => {
    plugins?.forEach(plugin => md.use(...plugin))
  }, [md, plugins])
}

首先,我不知道如何将模板参数添加到第二个插件定义中。

这不起作用:

[<T = any>MarkdownIt.PluginWithOptions<T>, T?]

但大多数情况下,我希望 TS 编译器认识到使用md.use(...plugin)是安全的。它抱怨说,论点需要支持

Expected at least 1 argument, but git 0 or more An argument for 'plugin' was not provided. Type 插入 must have a '[Symbol.iterator]()' method that returns an interator

更改我的线路以手动处理数组案例:

plugins?.forEach(plugin => Array.isArray(plugin) ? md.use(...plugin) : md.use(plugin))

删除迭代器错误消息,但也保留另一个以供使用...plugin

4

1 回答 1

0

You are passing all three cases to md.use with spread syntax, so they all have to be tuples. In the case of PluginSimple, the arguments are a tuple of length 1.

type Plugin = [PluginSimple] |
  [PluginWithOptions, any] | 
  [PluginWithParams, ...any[]]
type Plugins = Plugin[]

Now for the error about requiring 1 or more arguments, we can make sure that typescript knows that there is always at least one argument by destructuring the first entry in the tuple separately from the rest. Based on our union type, we know that main is always defined and is one of the plugin types, while rest is any[] and will be [] for the simple plugin.

function useMarkdown(source: any, plugins: Plugins = []) {
  React.useEffect(() => {
    plugins.forEach(plugin => {
      const [main, ...rest] = plugin; 
      md.use(main, ...rest)
    })
  }, [md, plugins])
}

This isn't perfect because we aren't enforcing a match between the PluginWithOptions and its specific option type, but hopefully it's good enough for your use case. For more advanced typing, I would think about defining your own plugin object which holds a plugin and its arguments rather than using tuples.

于 2020-10-25T03:14:11.687 回答