除非在某些情况下,否则并不真正支持循环类型别名。(UPDATE TS 4.1,这些都是现在更多的支持,但我仍然倾向于表现flow()为对工作AsChain 是验证一个特定的功能阵列,而不是试图拿出一个Chain符合所有有效的功能阵列)
与其试图以 TypeScript 友好的方式表示您在那里编写的特定类型,我想我会备份并将您的问题解释为:我们如何键入一个flow()-like 函数,该函数将一个可变数字作为其参数单参数函数,其中每个单参数函数返回类型是下一个单参数函数的参数类型,就像一个链......并且它返回一个代表折叠链的单参数函数?
我有一些我认为有效的东西,但它非常复杂,使用了很多条件类型、元组传播和映射元组。这里是:
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 链接到代码