如何在TypeScript中编写通用的,类型安全的高阶函数?

时间:2018-10-13 17:21:05

标签: typescript

例如,假设我正在编写一个备忘函数,该函数接受一个函数并返回另一个函数。我想利用TypeScript,以便即使我事先不知道输入函数的类型,也可以确保输出函数具有与输入函数相同的类型。这是一些示例代码:

function wrap(fn) {
  return function(...args) {
    return fn(...args);
  };
}

function repeat1(a: string, b: number): string {
  return a.repeat(b);
}

const repeat2 = wrap(repeat1);

不幸的是,repeat2解析为类型(...args: any[]) => any。我似乎找不到一种将输入类型传播到输出类型的方式来表达wrap函数的方法。

1 个答案:

答案 0 :(得分:1)

您需要使用泛型和Tuples in rest parameters and spread expressions

function wrap<A extends any[], R>(fn: (...a: A) => R) {
  return function(...args: A) {
    return fn(...args);
  };
}

function repeat1(a: string, b: number): string {
  return a.repeat(b);
}

const repeat2 = wrap(repeat1); // inferred to const repeat2: (a: string, b: number) => string

以上版本不适用于通用功能。如果我们放弃任何实现类型的安全性,我们可以创建一个保留通用函数参数的版本(这是可以接受的折衷方案,因为我们可以获得更好的呼叫站点安全性,这一点更为重要)

function wrap<T extends Function>(fn: T): T {
    return function(...args: any[]) :any {
        return fn(...args);
    } as any;
}

wrap(<T>(x: T): T => x)