TypeScript中如何动态推导回调转Promise包装函数的泛型类型
实现方案
1. 定义类型工具与包装函数
// 从配置项中提取success回调的入参类型 type ExtractSuccessRes<T> = T extends { success?: (res: infer R) => any } ? R : never; // 从配置项中提取fail回调的入参类型 type ExtractFailRes<T> = T extends { fail?: (res: infer R) => any } ? R : never; function toAsync<OptType>(fn: (opt: OptType) => any) { return async ( // 若不需要支持用户传入自定义success/fail/complete,可将OptType替换为Omit<OptType, 'success'|'fail'|'complete'> opt: OptType ): Promise<ExtractSuccessRes<OptType>> => { return new Promise<ExtractSuccessRes<OptType>>((resolve, reject) => { fn({ ...(opt || {}), success: (res: ExtractSuccessRes<OptType>) => { // 若需要保留用户自定义的success回调逻辑,可保留下行 opt?.success?.(res); resolve(res); }, fail: (res: ExtractFailRes<OptType>) => { // 若需要保留用户自定义的fail回调逻辑,可保留下行 opt?.fail?.(res); reject(res); }, complete: (res: any) => { // 若需要保留用户自定义的complete回调逻辑,可保留下行 opt?.complete?.(res); } } as unknown as OptType); }); }; }
2. 使用示例
// 示例待包装函数类型定义 type RequestFailResType = { code: number; msg: string }; type RequestSuccessResType = { data: any; status: number }; type RequestCompleteResType = { type: 'success' | 'fail' }; function request(opt:{ fail?:(res:RequestFailResType)=>any; success?:(res:RequestSuccessResType)=>any; complete?:(res:RequestCompleteResType)=>any; url:string }):any{ // 原有业务逻辑 } // 直接调用包装函数,无需手动传入泛型 const asyncRequest = toAsync(request); // 自动推导类型为:asyncRequest (opt: { url:string, fail?:..., success?:..., complete?:... }) => Promise<RequestSuccessResType> // 调用时自动提示入参字段,返回值自动识别类型 asyncRequest({ url: '/api/test' }) .then(res => { /* res 自动识别为 RequestSuccessResType 类型 */ }) .catch(err => { /* err 自动识别为 RequestFailResType 类型 */ })
核心逻辑说明
- 仅需声明1个泛型参数
OptType,TS会自动从传入的待包装函数入参中推导该类型,无需手动传入 - 通过TS条件类型的
infer语法,直接从OptType中反向提取success、fail回调的入参类型,无需额外手动声明类型 - 可根据业务需求选择是否保留用户传入的自定义回调逻辑,类型推导不受影响
内容的提问来源于stack exchange,提问作者ucag
相关产品推荐
相关产品推荐

