Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 任意数量的泛型参数_Typescript_Generics_Typescript Typings_Typescript Generics - Fatal编程技术网

Typescript 任意数量的泛型参数

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

考虑任意数量的函数,每个函数接受一个参数并返回一个值(不要担心它们的作用,而不是重点):

这些函数可以这样链接(fp中可能有更好的术语),因为每个函数都将前一个函数的返回类型作为参数:

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>
}