typescript - 键入具有任意数量的不同参数的函数

标签 typescript typescript-generics

我有一个名为 pipeline() 的函数,它目前是这样输入的

function pipeline(firstFn: Function, ...fns: Function[]) {
  let previousFn = firstFn()
  for (const func of fns) {
    previousFn = func(previousFn)
  }
  return previousFn
}

如果我用它来流水线一些功能

const add = (x: number) => (y: number) => x+y
const result = pipeline(
   () => 4,
   add(2),
   add(4)
)
// 10

但是,使用此解决方案时,不会对函数的参数类型与先前函数的返回类型匹配进行类型检查,并且返回类型是简单的 any

我意识到这不能完全键入(例如,Promise.all([]) 在它放弃之前最多可以处理 10 个 promise )但我想对至少几个参数的调用进行类型检查。

最佳答案

一个简单的解决方案

在管道中每个函数的返回类型相同的情况下,这可以很容易地通过泛型实现:

function pipeline<T>(firstFn: () => T, ...fns: ((arg: T) => T)[]): T {
    let previousFn = firstFn()
    for (const func of fns) {
      previousFn = func(previousFn)
    }

    return previousFn
}

更完整的解决方案

我们首先需要了解的是Promise.all 是如何实现的?

来自 typescript 来源lib.es2015.promise.d.ts :

all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;

all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;

all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;

...

all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;

他们为从 10 开始一直到通用包罗万象的每个元素数量的函数编写了一个重载。

这就是为什么 Promise.all 对返回的数组进行严格类型化会在超过 10 个不同类型的元素时退出。

如果您想复制此行为,则需要付出同样的努力。以下是最多三个参数的情况:

interface PipelineInterface {
    <T0, T1, T2>(a0: () => T0, a1: (a: T0) => T1, a2: (a: T1) => T2): T2;
    <T0, T1>(a0: () => T0, a1: (a: T0) => T1): T1;
    <T>(firstFn: () => T, ...fns: ((arg: T) => T)[]): T;
}

const pipeline: PipelineInterface = function (firstFn, ...fns) {
    let previousFn = firstFn()
    for (const func of fns) {
      previousFn = func(previousFn)
    }

    return previousFn
}

const result = pipeline(
    () => 4,
    (a) => a + 'Hello'
)
// result has type string

const result2 = pipeline(
    () => 4,
    (a: string) => a + 'Hello'
)
// Argument of type '(a: string) => string' is not assignable to parameter of type '(a: number) => string'.

关于typescript - 键入具有任意数量的不同参数的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54815926/

相关文章:

javascript - Angular 'PersonCtrl' 不是函数,未定义

javascript - 如何在 Typescript 中读取 json 响应

angular - 如何在 Angular2 中同时使用 httpInterceptor 和 configService?

javascript - TypeScript 无法缩小类型

reactjs - 根据对象中键的值定义类型

javascript - 空注入(inject)器错误: R3InjectorError(DynamicTestModule)[FormBuilder -> FormBuilder]: NullInjectorError: No provider for FormBuilder

空映射和数组的 typescript 类型

typescript - 如何在 Typescript 上对未知类型使用条件

typescript - 如何在 TypeScript 中使可为空的属性成为可选的?

typescript - 从数组类型泛型参数推断记录类型