TypeScript 如何在对象内约束函数签名 让onEnd参数匹配doAction返回类型
问题原因
你遇到的推导错误是TypeScript泛型推导优先级导致的死锁:
原写法将泛型T作为doAction返回Promise的内部类型,TS需要先确定doAction的返回值才能推导T,但你没有标注doAction的入参类型,TS又需要先知道T才能确定doAction的签名,最终T被推导为unknown,导致onEnd入参类型异常。
解决方案
重构泛型约束逻辑,让泛型直接匹配整个doAction函数类型,TS会优先用预设的入参约束推导doAction的参数类型,再提取返回值处理后赋值给onEnd的入参,完整实现如下:
export type $Unwrap<T> = T extends Promise<infer U> ? U : T extends (...args: any) => Promise<infer U> ? U : T extends (...args: any) => infer U ? U : T; type DoActionArgType = { contactId: string }; // 提取doAction返回值并解包的工具类型 type UnwrapActionReturn<T extends (arg: DoActionArgType) => any> = $Unwrap<ReturnType<T>>; // 泛型直接约束整个doAction函数 type Args<T extends (arg: DoActionArgType) => any> = { doAction: T; onEnd?: (arg: UnwrapActionReturn<T>) => void; } // 调整test函数的泛型约束 function test<T extends (arg: DoActionArgType) => any>(arg: Args<T>) {}
验证效果
你之前报错的场景可以正常运行,无需手动标注doAction入参类型:
test({ doAction: async ({ contactId }) => 1, // contactId自动推导为string,返回值推导为Promise<number> onEnd: (arg) => { const a:number = arg // arg正确推导为number,无类型错误 } }) // 其他场景也全部兼容: // 1. 外置doAction变量 const doAction = async ({ contactId }) => 1 test({ doAction, onEnd: (arg) => { const a:number = arg } }) // 2. 无入参的doAction test({ doAction: async () => 'test', onEnd: (arg) => { const a:string = arg } }) // 3. 同步返回的doAction test({ doAction: ({ contactId }) => true, onEnd: (arg) => { const a:boolean = arg } })
内容的提问来源于stack exchange,提问作者Philiiiiiipp
相关产品推荐
相关产品推荐

