我有一个接受回调的方法有多个重载的类。
我想改为以Promise
为基础,但我在使用TypeScript泛型时以类型安全的方式执行此操作时遇到了麻烦。
基本上API就是这样:
class CallbackClient {
method(req: Request, callback: (error: Error, response: Response) => void): void
method(req: Request, options: Options, callback: (error: Error, response: Response) => void): void
}
应该成为这个:
class PromiseClient {
method(req: Request): Promise<Response>
method(req: Request, options: Options): Promise<Response>
}
但是如何在TypeScript中将PromiseClient
定义为泛型类型?
在伪代码中,我想要一个这样的类型:
type PromiseClient<T> = {
[P in keyof T]: (args of T[P] without the callback) => Promise<response of T[P] in callback>
}
我有一个实现可以实现这一点,但由于我无法实现这一点,因此我放弃了类型安全。
映射它的功能如下:
function toPromiseClient<T extends CallbackClient>(client: T): PromiseClient<T> {
const promiseClient: PromiseClient<T> = {}
Object.keys(Object.getPrototypeOf(client))
.forEach((functionName: string) => {
const originalFunction = client[functionName as keyof T]
if (!originalFunction) {
return
}
promiseClient[functionName as keyof T] = (...args: any[]) => new Promise<any>((resolve, reject) => {
if (args && args.length > 1 && typeof (args[args.length - 1]) === 'function') {
reject(new Error('Use Promise API instead of callbacks'))
return
}
originalFunction.call(client, ...args, (error: Error, res: any) => {
if (error) {
reject(error)
return
}
resolve(res)
})
})
})
return promiseClient
}
答案 0 :(得分:2)
这在部分原型2.8中有部分可能(尚未发布,应该在2018年3月发布,如果通过npm install -g typescript@next
则可以获得)
解决方案:
declare class CallbackClient {
method1(req: Request, options: Options, callback: (error: Error, response: Response) => void): void
method1(req: Request, callback: (error: Error, response: Response) => void): void
method2(req: Request, options: Options, callback: (error: Error, response: Response) => void): void
method3(req: Request, options?: Options, callback?: (error: Error, response: Response) => void): void
}
type Promisify<T> = {
[P in keyof T]:
T[P] extends (callback: (error: Error, response: infer TResponse) => void) => void ? () => Promise<TResponse> :
T[P] extends (p1: infer P1, callback: (error: Error, response: infer TResponse) => void) => void ? (p1: P1) => Promise<TResponse> :
T[P] extends (p1: infer P1, p2: infer P2, callback: (error: Error, response: infer TResponse) => void) => void ? (p1: P1, p2: P2) => Promise<TResponse> :
T[P] extends (p1: infer P1, p2: infer P2, p3: infer P3, callback: (error: Error, response: infer TResponse) => void) => void ? (p1: P1, p2: P2, p3: P3) => Promise<TResponse> :
never;
}
type PromiseClient = Promisify<CallbackClient>;
// Will be equivalent to :
// type PromiseClient = {
// method1: (p1: Request) => Promise<Response>; // Only one overload, not the second
// method2: (p1: Request, p2: Options) => Promise<Response>;
// method3: (p1: Request, p2: Options | undefined) => Promise<Response>;
// }
上面的解决方案使用条件类型从原始类的每个方法中提取参数类型,然后使用这些类型为返回promise的方法创建新的函数类型。
限制:
ArgType | undefined
method1: (p1: Request) => Promise<Response>
我们也没有得到method1: (p1: Request, p2: Options) => Promise<Response>
(并且根据重载的顺序,您可能会得到奇怪的结果,这很古怪)。