TypeScript带extends子句的泛型未按预期收窄的原因是什么
推导差异的核心原因
这个现象是TypeScript泛型的推导规则和约束上下文的差异导致的,分两种情况说明:
test函数的推导逻辑test只有一个泛型参数U,且它的约束是固定的具体类型MyType。TypeScript推导U的时候仅参考入参args的类型,传入的val2、val3都是const定义的字面量类型,二者都满足extends MyType的约束,所以U会被推导为最窄的联合类型'val2' | 'val3'。test2函数的推导逻辑test2存在两个有依赖关系的泛型参数T和U extends T,推导分两步执行:
- 首先推导
T的类型:T的唯一推导源是第一个入参value,你传入的variable已经通过as MyType断言为完整的三值联合类型,所以T直接被确定为MyType。 - 再推导
U的类型:虽然后续入参val2、val3的类型候选是'val2' | 'val3',但因为U的约束是extends T,而T已经被固定为MyType,TypeScript默认会优先保证泛型参数的约束兼容性,将U拓宽到和T对齐的最宽兼容类型,也就是完整的MyType。
如果需要让test2的U也只从后续入参推导,不被T的类型拓宽,可以使用TypeScript 4.7新增的NoInfer工具类型修改函数定义,切断T对U推导的影响:
declare function test2<T, U extends T>(value: NoInfer<T> | undefined, ...values: U[]): void; // 修改后调用test2(variable, val2, val3),U会被推导为预期的'val2' | 'val3'
内容的提问来源于stack exchange,提问作者Guerric P
相关产品推荐
相关产品推荐

