关于TypeScript 2.8条件类型与MockedImplementation的使用疑问
先理清楚你的核心诉求:你想让MockedImplementation<F>支持三种输入形式——和F完全匹配的函数、F的返回值类型,以及当F返回Promise时,直接用Promise解析后的值;然后由mockIt()来做对应的包装。现在SomeOperationA的mockIt能正常跑,但其他带重载的函数可能出问题,不确定是自己用错了还是版本Bug。
我从几个方向帮你分析下:
先检查你的Conditional Types定义是否准确
首先,你的MockedImplementation<F>应该是类似这样的条件类型吧?
type MockedImplementation<F extends (...args: any[]) => any> = | F // 匹配原函数签名 | ReturnType<F> // 直接返回原函数的返回值类型 | (ReturnType<F> extends Promise<infer T> ? T : never); // 如果返回是Promise,支持解析后的值
如果这里的定义有问题——比如没把F约束为函数类型,或者Promise的泛型推断写错了,那肯定会出问题。不过既然SomeOperationA能正常工作,大概率这部分是对的。
函数重载才是可能的“罪魁祸首”
TypeScript的条件类型在处理重载函数时,有个容易踩坑的点:ReturnType<F>只会取最后一个重载的返回类型,而不是所有重载的联合类型。
举个例子,假设你有个重载函数:
function SomeOperationB(a: string): Promise<string>; function SomeOperationB(a: number): number; function SomeOperationB(a: string | number): Promise<string> | number { // 具体实现 }
这时候ReturnType<typeof SomeOperationB>得到的是number(最后一个重载的返回值),而不是你预期的Promise<string> | number。这就导致你的MockedImplementation<F>没法正确覆盖第一个重载的Promise场景,自然会出现类型不兼容的问题——而SomeOperationA没有重载,ReturnType能正确推断,所以一切正常。
怎么区分是使用问题还是版本Bug?
可以做这几个测试验证:
- 手动给
mockIt()指定泛型参数,比如mockIt<typeof SomeOperationB>(...),看看类型推断是否正常。如果手动指定后没问题,那就是TypeScript自动推断重载函数泛型时的问题。 - 去TypeScript的GitHub仓库搜搜开发版本的已知Issue,看看有没有人报过类似的“重载函数+条件类型”的Bug——毕竟这是2.8.0的开发版,还没正式发布,存在未修复的问题很正常。
总结
目前来看,更可能是TypeScript开发版本在处理重载函数与条件类型交互时的Bug,而非你的使用方式有误。不过还是建议再核对下MockedImplementation的条件类型定义,确保逻辑覆盖了所有预期场景。如果确认定义没问题但重载函数依然报错,那可以去TypeScript的官方仓库提交Issue反馈这个问题。
内容的提问来源于stack exchange,提问作者Jason Kleban

