除非在某些情况下,否则并不真正支持循环类型别名。 (更新 TS 4.1,这些现在得到更多支持,但我仍然倾向于将 flow() 表示为在 AsChain 上运行,验证特定的函数数组,而不是试图提出一个Chain 匹配所有有效函数数组)
与其试图以 TypeScript 友好的方式表示您在那里编写的特定类型,我想我会备份并将您的问题解释为:我们如何键入类似 flow() 的函数,它需要作为其参数的可变数量的单参数函数,其中每个单参数函数的返回类型是下一个单参数函数的参数类型,就像一个链......并且它返回一个单参数函数,表示倒塌的链条?
我有一些我认为可行的方法,但它非常复杂,使用了很多 conditional types、tuple spreads 和 mapped tuples。这里是:
type Lookup<T, K extends keyof any, Else=never> = K extends keyof T ? T[K] : Else
type Tail<T extends any[]> = T extends [any, ...infer R] ? R : never;
type Func1 = (arg: any) => any;
type ArgType<F, Else=never> = F extends (arg: infer A) => any ? A : Else;
type AsChain<F extends [Func1, ...Func1[]], G extends Func1[]= Tail<F>> =
{ [K in keyof F]: (arg: ArgType<F[K]>) => ArgType<Lookup<G, K, any>, any> };
type Last<T extends any[]> = T extends [...infer F, infer L] ? L : never;
type LaxReturnType<F> = F extends (...args: any) => infer R ? R : never;
declare function flow<F extends [(arg: any) => any, ...Array<(arg: any) => any>]>(
...f: F & AsChain<F>
): (arg: ArgType<F[0]>) => LaxReturnType<Last<F>>;
让我们看看它是否有效:
const stringToString = flow(
(x: string) => x.length,
(y: number) => y + "!"
); // okay
const str = stringToString("hey"); // it's a string
const tooFewParams = flow(); // error
const badChain = flow(
(x: number)=>"string",
(y: string)=>false,
(z: number)=>"oops"
); // error, boolean not assignable to number
我觉得不错。
我不确定是否值得详细了解类型定义的工作原理,但我不妨解释一下如何使用它们:
-
Lookup<T, K, Else> 尽可能返回T[K],否则返回Else。所以Lookup<{a: string}, "a", number> 是string,Lookup<{a: string}, "b", number> 是number。
-
Tail<T> 采用元组类型T 并返回一个删除了第一个元素的元组。所以Tail<["a","b","c"]> 是["b","c"]。
-
Func1 只是单参数函数的类型。
-
ArgType<F, Else> 如果是单参数函数,则返回 F 的参数类型,否则返回 Else。所以ArgType<(x: string)=>number, boolean> 是string,ArgType<123, boolean> 是boolean。
-
AsChain<F> 接受一个单参数函数的元组并尝试将其变成一个链,方法是将F 中每个函数的返回类型替换为下一个函数的参数类型(并使用any 表示最后一个)。如果AsChain<F> 与F 兼容,那么一切都很好。如果AsChain<F>与F不兼容,那么F就不是一个好的链。所以,AsChain<[(x: string)=>number, (y:number)=>boolean]> 是[(x: string)=>number, (y: number)=>any],这很好。但是AsChain<[(x: string)=>number, (y: string)=>boolean]>是[(x: string)=>string, (y: string)=>any],这样不好。
-
Last<T> 接受一个元组并返回最后一个元素,我们需要用它来表示flow() 的返回类型。 Last<["a","b","c"]> 是 "c"。
-
最后,LaxReturnType<F> 与ReturnType<F> 一样,但对F 没有限制。
好的,希望对您有所帮助;祝你好运!
Playground link to code