Typescript 任意数量的泛型参数
考虑任意数量的函数,每个函数接受一个参数并返回一个值(不要担心它们的作用,而不是重点): 这些函数可以这样链接(fp中可能有更好的术语),因为每个函数都将前一个函数的返回类型作为参数:Typescript 任意数量的泛型参数,typescript,generics,typescript-typings,typescript-generics,Typescript,Generics,Typescript Typings,Typescript Generics,考虑任意数量的函数,每个函数接受一个参数并返回一个值(不要担心它们的作用,而不是重点): 这些函数可以这样链接(fp中可能有更好的术语),因为每个函数都将前一个函数的返回类型作为参数: type Fn<I, O> = (input: I) => O function chain(...fns: Fn<any, any>[]): Fn<any, any> { return (input: any) => { let result = i
type Fn<I, O> = (input: I) => O
function chain(...fns: Fn<any, any>[]): Fn<any, any> {
return (input: any) => {
let result = input
for (const fn of fns) {
result = fn(result)
}
return result
}
}
const chained = chain(toNumber, toBoolean, toString)
const result = chained('5') // returns "true"
但是有更好的方法吗?我不确定我会称之为更好的方法,但可以将此规则编码到类型系统中。然而,如果没有良好的文档,大多数观察者可能很难理解它的作用
下面的方法使用了一个泛型参数,
扩展了readonlyray,这太神奇了,我对类型系统有太多不知道的地方。。。
type Fn<I, O> = (input: I) => O
function chain(...fns: Fn<any, any>[]): Fn<any, any> {
return (input: any) => {
let result = input
for (const fn of fns) {
result = fn(result)
}
return result
}
}
const chained = chain(toNumber, toBoolean, toString)
const result = chained('5') // returns "true"
declare function chain<S, T1>(fn: Fn<S, T1>): Fn<S, T1>
declare function chain<S, T1, T2>(fn1: Fn<S, T1>, fn2: Fn<T1, T2>): Fn<S, T2>
declare function chain<S, T1, T2, T3>(fn1: Fn<S, T1>, fn2: Fn<T1, T2>, fn3: Fn<T2, T3>): Fn<S, T3>
type Fn<I, O> = (input: I) => O;
type Input<F> = F extends Fn<infer U, any> ? U : never;
// or you can use ReturnType<T>, which is provided by typescript
type Output<F> = F extends Fn<any, infer U> ? U : never;
// first elem of tuple type
type Head<T> = T extends [infer U, ...unknown[]] ? U : never;
// all but first elem of tuple type
type Tail<T> = T extends [unknown, ...(infer U)] ? U : never;
// last element of array, only works on typescript 4.2+
type Last<T> = T extends [...unknown[], infer U] ? U : never;
// `true` if T can be composed with U, `false` if not, and `never` if the types are wrong
type CanCompose<T, U> = T extends Fn<any, infer Output>
? (
U extends Fn<infer Input, any>
? (Input extends Output ? true : false)
: never
)
: never;
// Evaluates to a tuple of booleans. If any element in the tuple is false, you cannot compose the whole array of T.
type IsComposable<T> = T extends Fn<any, any>[]
? CanCompose<Head<T>, Head<Tail<T>>> extends true
? (
Tail<T> extends never[]
? [true]
: [true, ...(IsComposable<Tail<T>>)]
)
: [false]
: [false];
type Composable<T> = IsComposable<T> extends true[] ? T : never[];
type ComposedFunction<T> = IsComposable<T> extends true[]
? Fn<Input<Head<T>>, Output<Last<T>>>
: Fn<never, never>;
function chain<T extends ReadonlyArray<Fn<any, any>>>(...fns: Composable<T>): ComposedFunction<T> {
return ((x: Input<Head<T>>) => {
let result = x;
for (const fn of fns) {
result = fn(result);
}
return result;
}) as ComposedFunction<T>
}