类型的 Typescript 扩展运算符
Typescript spread operator for type
我正在尝试定义一种类型,它获取一个函数类型作为泛型参数,returns 一个与输入函数类型相同的函数类型,只是它在末尾多了一个参数:
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 元函数定义一个这样的类型。
TypeScript 可以相当容易地表示 prepending 一个类型到一个元组类型上,称为 Cons<H, T>
像这样:
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<T, V>
到 将类型追加 到元组末尾:
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,或者如果它来自函数的参数列表,您会注意到编译器 "shifts" 可选标记和参数名称向右移动一个元素:
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
好的,希望对您有所帮助。祝你好运!
我正在尝试定义一种类型,它获取一个函数类型作为泛型参数,returns 一个与输入函数类型相同的函数类型,只是它在末尾多了一个参数:
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 元函数定义一个这样的类型。
TypeScript 可以相当容易地表示 prepending 一个类型到一个元组类型上,称为 Cons<H, T>
像这样:
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<T, V>
到 将类型追加 到元组末尾:
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,或者如果它来自函数的参数列表,您会注意到编译器 "shifts" 可选标记和参数名称向右移动一个元素:
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
好的,希望对您有所帮助。祝你好运!