类型的打字稿传播运算符[重复]

Posted

技术标签:

【中文标题】类型的打字稿传播运算符[重复]【英文标题】:Typescript spread operator for type [duplicate] 【发布时间】:2020-03-01 22:20:03 【问题描述】:

我正在尝试定义一种类型,该类型将函数类型作为泛型参数并返回与输入函数类型相同的函数类型,只是它最后多了一个参数:

  type AugmentParam<F extends (...args: any[]) => any, ExtraParam> = F extends (
    ...args: infer Args
  ) => infer R
    ? (
        ...args: [
          ...Args,
          ExtraParam
        ]
      ) => R
    : never

用法示例:

type F = (x: number) => boolean
type F2 = AugmentParam<F, string> // (x: number, arg2: string) => boolean

...Args 似乎不起作用,但是如果我将其更改为这样的东西,它会起作用:

  type AugmentParam<F extends (...args: any[]) => any, ExtraParam> = F extends (
    ...args: infer Args
  ) => infer R
    ? (
        ...args: [
          Args[0],
          Args[1] /* Spread doesn't work here, so it doesn't work for arbitrary number of arguments :( */,
          ExtraParam
        ]
      ) => R
    : never

但它只适用于特定数量的参数,我需要为每个 n 元函数定义一个这样的类型。

【问题讨论】:

【参考方案1】:

TypeScript 可以很容易地将一个类型添加到一个元组类型上,称为Cons&lt;H, T&gt;,如下所示:

type Cons<H, T extends readonly any[]> =
    ((h: H, ...t: T) => void) extends ((...r: infer R) => void) ? R : never

type ConsTest = Cons<1, [2, 3, 4]>;
// type ConsTest = [1, 2, 3, 4]

您可以将此定义与条件映射元组类型一起使用,以生成Push&lt;T, V&gt; 以将类型追加到元组的末尾:

type Push<T extends readonly any[], V> = Cons<any, T> extends infer A ?
     [K in keyof A]: K extends keyof T ? T[K] : V  : never

type PushTest = Push<[1, 2, 3], 4>;
// type PushTest = [1, 2, 3, 4]

但是Push 的这个定义是脆弱的。如果T 元组有optional elements,或者如果它来自函数的参数列表,您会注意到编译器将可选标记和参数名称“移动”到右侧一个元素:

type Hmm = (...args: Push<Parameters<(optStrParam?: string) => void>, number>) => void;
// type Hmm = (h: string | undefined, optStrParam?: number) => void

参数名称实际上并不是类型的一部分,因此虽然很烦人,但它不会影响实际类型。在可选参数之后附加一个参数是......奇怪,所以我不确定那里的正确行为。不确定这些是否会破坏您的交易,但请注意。

无论如何,您的AugmentParam 看起来像:

type AugmentParam<F extends (...args: any[]) => any, ExtraParam> =
    (...args: Extract<Push<Parameters<F>, ExtraParam>, readonly any[]>)
        => ReturnType<F>

并且它有效(带有前面的警告):

type F = (x: number) => boolean

type F2 = AugmentParam<F, string>
// type F2 = (h: number, x: string) => boolean

type F3 = AugmentParam<F2, boolean>
// type F3 = (h: number, h: string, x: boolean) => boolean

好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

哇!非常感谢! 看来“转变”问题对我的情况很重要。我试图将它与这种类型一起使用:(text: string, html: string|undefined, editorState: EditorState) =&gt; DraftHandleValue 我正在定义这样的类型:AugmentParam&lt;EditorProps['handleKeyCommand'], PluginFunctions&gt; 但它似乎没有按预期工作。 抱歉,信息不足,我无法提供帮助。您能以minimal reproducible example 表示您的问题吗?

以上是关于类型的打字稿传播运算符[重复]的主要内容,如果未能解决你的问题,请参考以下文章

打字稿和传播运算符?

打字稿:传播类型只能从对象类型创建

如何在打字稿中避免这种符号“| undefined”?

!对象方法后打字稿中的运算符

!对象方法后打字稿中的运算符

为啥在数组上使用 ?: 运算符时打字稿不需要`undefined`? [复制]