TypeScript泛型extends与直接extends语句的类型行为差异疑问
为什么泛型
IfExtends和直接条件判断的结果不一样? 这事儿的核心原因是TypeScript的分布式条件类型在起作用,咱们一步步拆解来看:
首先先明确几个基础:
interface empty { }的keyof empty类型就是never,因为空接口没有任何属性键。- 泛型里的
T extends B和直接写的条件判断X extends Y ? A : B,在处理联合类型(包括never这种空联合)时逻辑完全不同。
1. 变量a的情况:泛型IfExtends触发了分布式条件类型
当你在泛型条件类型中使用T extends B时,如果T是一个联合类型(哪怕是空联合never),TypeScript会自动触发「分布式条件类型」的逻辑:把联合类型的每个成员单独拿出来,分别和B进行extends判断,最后把所有结果再合并成一个联合类型。
而never是一个空的联合类型——它没有任何成员可以拆分出来进行判断,所以整个条件类型的结果就直接是never,这就是为什么a的类型是never。
2. 变量b的情况:直接条件判断是非分布式的
而keyof empty extends never ? number : string这种写法,属于非分布式的条件类型:这里的extends是直接对整个类型(也就是never)进行判断,没有拆分联合类型的逻辑。
在TypeScript的类型系统里,never extends never是成立的(因为never是所有类型的子类型,包括它自己),所以这个条件判断会返回number,也就是b的类型是number。
举个更直观的例子验证
咱们换个非空的联合类型试试,你就能更清楚分布式和非分布式的区别:
type IfExtends<T, B, Y, N> = T extends B ? Y : N; // 分布式:把'a'和'b'分别判断,结果是number | string type Test1 = IfExtends<'a' | 'b', 'a', number, string>; // 非分布式:整个联合类型'a'|'b'不extends 'a',结果是string type Test2 = 'a' | 'b' extends 'a' ? number : string;
这样对比下来,你就能明白为什么同样是extends判断,泛型版本和直接写法会有不同结果啦~
内容的提问来源于stack exchange,提问作者lei li
相关产品推荐
相关产品推荐

