如何使用嵌套泛型参数定义TypeScript类型别名?
解决TypeScript中从嵌套泛型类型提取参数的问题
你遇到的问题本质是需要从已有的Handler<I, R>类型中自动提取出I和R,而不需要手动重复传入这两个类型参数。TypeScript的条件类型+infer关键字正好可以解决这个问题,让你实现只传入Handler类型就能生成对应的异步处理函数类型。
直接解决方案
你只需要用infer在条件类型中推断Handler的泛型参数,修改AsyncHandler的定义如下:
type NodeCallback<T> = (err?: Error | void, result?: T) => void type Handler<I, R> = (event: I, callback: NodeCallback<R>) => void type StrToNumHandler = Handler<string, number> // 正确的AsyncHandler定义 type AsyncHandler<T extends Handler<any, any>> = T extends Handler<infer I, infer R> ? (event: I) => Promise<R> : never; // 现在可以直接传入StrToNumHandler,无需额外传I和R type AsyncStrToNumHandler = AsyncHandler<StrToNumHandler>; // 等价于:(event: string) => Promise<number>
原理说明
T extends Handler<any, any>:先约束T必须是Handler的某个具体实例类型;T extends Handler<infer I, infer R>:使用infer关键字告诉TypeScript,当T匹配Handler<I, R>的结构时,自动推断出I(输入事件类型)和R(回调结果类型);- 最后返回
(event: I) => Promise<R>,也就是把原来的回调式Handler转换成Promise风格的异步函数类型。
可选:提取通用工具类型
如果需要复用Handler的输入/输出类型提取逻辑,可以单独定义工具类型:
// 提取Handler的输入事件类型 type HandlerInput<T extends Handler<any, any>> = T extends Handler<infer I, any> ? I : never; // 提取Handler的回调结果类型 type HandlerOutput<T extends Handler<any, any>> = T extends Handler<any, infer R> ? R : never; // 基于工具类型定义AsyncHandler type AsyncHandler<T extends Handler<any, any>> = (event: HandlerInput<T>) => Promise<HandlerOutput<T>>;
这种写法更清晰,后续如果需要单独获取某个Handler的输入或输出类型,直接用HandlerInput<StrToNumHandler>或HandlerOutput<StrToNumHandler>即可。
验证效果
现在你可以像期望的那样使用AsyncHandler,TypeScript会自动推导出正确的类型:
const asyncHandler: AsyncStrToNumHandler = (event) => { return Promise.resolve(event.length); // event被推断为string,返回值是Promise<number> };
这样就彻底解决了重复传入类型参数的问题,代码更简洁且类型安全。
内容的提问来源于stack exchange,提问作者bilalq
相关产品推荐
相关产品推荐

