假设现在我有一个函数: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 这个函数类型,也是死了不少脑细胞。故有此文。