最近,我正在研究第三方图书馆的“Promision”。基本上,库中充满了NodeJS异步风格的函数(使用回调作为最后一个参数)。一、 e.具有类似于此签名的功能:
function foo(arg1: string, arg2: number, ..., callback: (error, result) => void): void
我试图编写一个函数,以减少包装原始函数的代码,并将其转换为
Promise<T>
返回的:
function cb<TResult>(
resolve: (res: TResult) => void,
reject: (err: any) => void
): (actualError, actualResult) => void {
return (error, result) => error ? reject(error) : resolve(result);
}
然后,为了证明这些方法,我将编写如下代码:
patchUserMetadata(userId: string, userMetadata: any): Promise<a0.Auth0UserProfile> {
return new Promise((resolve, reject) =>
this.wrapped.patchUserMetadata(userId, userMetadata, cb(resolve, reject)));
}
linkUser(userId: string, secondaryUserToken: string): Promise<any> {
return new Promise((resolve, reject) =>
this.wrapped.linkUser(userId, secondaryUserToken, cb(resolve, reject)));
}
// ... and so on, and on, and on...
有人审查了我的代码,指出我可以使用
js-promisify
以较低的成本实现类似的结果。库定义了一个执行此任务的助手:
module.exports = function (fun, args, self) {
return new Promise(function (resolve, reject) {
args.push(function (err, data) {
err && reject(err);
resolve(data);
})
fun.apply(self, args);
});
};
因为我处理的是TypeScript而不是JavaScript,所以我进一步做了一些研究。这就是我最终选择的原因
typed-promisify
现在代码是这样的:
patchUserMetadata = promisify(this.wrapped.patchUserMetadata);
linkUser = promisify(this.wrapped.linkUser);
越来越近
我想知道这到底是怎么回事
promisify
功能工作?我查看了源代码,找到了一个类似的解决方案
js promisify公司
的一个:
export function promisify<T>(f: (cb: (err: any, res: T) => void) => void, thisContext?: any): () => Promise<T>;
export function promisify<A, T>(f: (arg: A, cb: (err: any, res: T) => void) => void, thisContext?: any): (arg: A) => Promise<T>;
export function promisify<A, A2, T>(f: (arg: A, arg2: A2, cb: (err: any, res: T) => void) => void, thisContext?: any): (arg: A, arg2: A2) => Promise<T>;
export function promisify(f: any, thisContext?: any) {
return function () {
let args = Array.prototype.slice.call(arguments);
return new Promise((resolve, reject) => {
args.push((err: any, result: any) => err !== null ? reject(err) : resolve(result));
f.apply(thisContext, args);
});
}
}
问题
如果你看看
仔细观察,你会发现这个解并不是真正的广义解。也就是说,如果我需要提供一个包含10个以上参数的函数,那么它就不会有匹配的重载。实现仍然可以正常工作,但是在这种情况下类型信息会丢失。
TypeScript中有没有一种方法可以推断出精确的函数类型(或签名,或参数的计数和类型),而不必预先定义所有那些讨厌的重载?
我正在寻找这样的东西(显然是伪代码):
export function promisify<...[TArgs], T>(
f: (...allArgsButLastTwo: [TArgs],
cb: (err: any, res: T) => void) => void,
thisContext?: any
): (...[TArgs]) => Promise<T>;
export function promisify(
...allArgsButLastTwo: any[],
f: any,
thisContext?: any
) {
return function () {
let args = Array.prototype.slice.call(arguments);
return new Promise((resolve, reject) => {
args.push((err: any, result: any) => err !== null ? reject(err) : resolve(result));
f.apply(thisContext, args);
});
}
}
不
这就是为什么长重载列表是作者不得不使用的最后手段/折衷方案。