TypeScript–普通函数 Promise 化

假设现在我有一个函数:add

/**
 * add numbers
 * @param rest
 */
function add (...rest: number[]): number {
  let res = 0
  for (let i = 0, len = rest.length; i < len; i++) {
    res += rest[i]
  }
  return res
}

现在,我想将其包装成 Promise 函数:

function promisedAdd(...rest: number[]): Promise<number> {
  return new Promise((resolve) => resolve(add(...rest)))
}

我还有一个函数 sub,其参数和返回值与 add 一致。为了将 sub 也 Promise 化,我可以将上面的包装函数改写一下。但如果,我还有 n 个函数(参数和返回值可能不一样)也需要 Promise 化,难道我需要将包装函数写 n 遍吗?

其实如果没有使用 TypeScript 还好,直接一个 JavaScript 函数完事。但用了 TypeScript 就有了一个需要解决的问题:类型。

对于这种多变的类型,需要使用泛型,并且参数类型和返回值类型要从被包装的函数取,于是,有了下面的类型:

export type WorkerCallPromisify<T extends (...args: any) => any> = (
  ...rest: Parameters<T>
) => Promise<ReturnType<T>>

Parameters 获取函数参数类型,ReturnType 获取函数返回值类型。至于为什么叫 WorkerCallPromisify?那是为了让函数在 worker 中运行时可以通过 Promise 的方式调用——Message 通信 Promise 封装。

本身就对 TypeScript 一知半解,为了得到 WorkerCallPromisify 这个函数类型,也是死了不少脑细胞。故有此文。