我想创建一个功能链,该功能链是管道/流程/组成功能的输入。
是否可以像通常那样处理,而无需将字面量扩展到选定的深度? See lodash's flow。
我想实现链中数据流的类型检查。 -函数的参数是前一个的结果 -第一个参数是模板参数 -最后返回的是模板参数
type Chain<In, Out, Tmp1 = any, Tmp2 = any> = [] | [(arg: In) => Out] | [(arg: In) => Tmp1, (i: Tmp1) => Tmp2, ...Chain<Tmp2, Out>];
这个想法在草案中。
这会产生以下错误:
Type alias 'Chain' circularly references itself.
(理解原因,不知道如何解决)A rest element type must be an array type.
(普通元组可能不可用价差)Type 'Chain' is not generic.
(甚至不知道为什么出现此错误)在打字稿中是否可以定义Chain
?如果是这样,请附上摘要。
(在最新的tsc 3.1.6
上进行了测试)
答案 0 :(得分:6)
除非在某些情况下,否则实际上不支持圆形类型别名。我想我不会备份并以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: T) => void) extends ((x: any, ...u: infer U) => void) ? U : 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 LastIndexOf<T extends any[]> =
((...x: T) => void) extends ((y: any, ...z: infer U) => void)
? U['length'] : never
declare function flow<F extends [(arg: any) => any, ...Array<(arg: any) => any>]>(
...f: F & AsChain<F>
): (arg: ArgType<F[0]>) => ReturnType<F[LastIndexOf<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]
,不好。
最后,LastIndexOf<T>
取一个元组并返回最后一个索引,我们需要用它表示flow()
的返回类型。 LastIndexOf<["a","b","c"]>
是2
。
好的,希望能有所帮助;祝你好运!