还有这样的TypeScript类型,我们来猜猜res是什么:第一:传入的类型参数是联合类型1|'a',res是什么类型?Test=Textendsnumber?1:2;输入res=Test<1|'一个'>;第二:传入的类型参数是boolean,resTest=Textendstrue是什么类型?1:2;输入res=Test;第三:传入的类型参数是any,什么是restypeTest=Textendstrue?1:2;输入res=Test;第四:传入的类型参数是never,什么是res?类型Test=Textendstrue?1:2;输入res=Test;我自己的答案,接下来我会公布正确答案,大家看看猜对了多少。答案揭晓。第一类res是1|2、再看第二种,res也是1|2,那么第三种,res也是1|2、最后是第四种,res是never,不管答对多少都没关系,关键是要知道它的道理。接下来解释一下:第一类res是1|2.可能有同学会说,这里输入的是连体类型,不是数字。为什么?结果是这样的?因为当条件类型的左边是类型参数时,它会具有分布式的性质,即把联合类型的每一个类型分别传入求值,将各自的结果组合成一个联合类型。这称为分配公式条件类型。这里的Textendsnumber左边是类型参数T,输入是关节类型1|'a',所以1会被传入evaluation,2会被传入evaluation,最后将结果合并为jointtype,即1|2。我们再来看第二种。Res也是1|2.为什么也是1|2在这里?刚才说的分布式条件类型是针对联合类型的?是的,boolean其实是一个联合类型,所以true和false会结合评估分别传入,最后的结果结合成一个联合类型,所以就是1|2、接下来是第三种,res也是1|2个同学可能会说:哦,原来如此,any也是联合类型。错了,any不是联合类型,这是因为条件类型对any有特殊处理,如果左边是any,那么直接把trueType和falseType组合成联合类型返回。最后,还有第四种。res是never,所以没有never,不就是1和2吗?这确实是对TS的一种特殊对待。当条件类型左边为never时,直接返回never。你说了那么多,我怎么知道是不是真的?如果你弥补了怎么办?有疑虑是正常的,这是我们应该有的态度,但这些确实是事实。接下来,我会从源码上验证下来。从TS源码解释原因这里的重点不在于如何阅读TypeScript源码,我会跳过过程直接给出结果。对如何阅读TypeScript源码感兴趣的同学可以看我之前的文章:《我读 TypeScript 源码的秘诀都在这里了》,或者看我刚刚推出的掘金小册子《TypeScript 类型体操通关秘籍》,里面会从源码原理上讲解各种类型的TypeScript。先解释一下第一种联合类型+条件类型的情况:typeTest=Textendsnumber?1:2;输入res=Test<1|'一个'>;当TypeScript处理条件类型ConditionalType时,会根据类型参数是否为checkType(左边的类型)设置一个isDistributive属性。因为Textendsnumber的checkType是T,所以这里的isDistributive为true,即是分布式条件类型。那么分布式条件类型会做什么呢?每种类型在评估时会单独传入评估,最后合并结果。对应的源码是这样的:这里不用解释,注释很清楚,TextendsU?X:Y当传入的T为A|B,结果是(AextendsU?X:Y)|(BextendsU?X:Y)。这就是分布式条件类型遇到联合类型时发生的情况。所以,源码来到了mapTypeWithAlias这个分支,也就是分别做每个类型的求值。我们已经从源码中验证了分布式条件类型的特性!接下来看第二种,当条件类型+boolean:typeTest=Textendstrue?1:2;输入res=Test;前面说过boolean也是一种联合类型。这是真的?debug发现也走到了这个分支。说明条件为真,boolean是union还是never验证:这里的flags是每一位代表一个类型,然后通过位运算的按位AND判断是否是那个类型:这种方式占用空间小,计算速度快,许多框架以这种方式识别类型,例如React。因此,从结果来看,boolean是一个联合类型,即true|错误的。那自然会触发分布式条件类型的特性,分别传递true和false进行评估,最后合并结果。然后就是第三种,当条件type+any:typeTest=Textendstrue?1:2;输入res=Test;debug会发现并没有走到mapType的分支,而是跑到另外一个分支:这说明条件不满足,any不是union类型,我们也可以通过flags看到:按位与的结果是0,这也表明它不是并集,也不是从不。那为什么结果还是1|2?继续往下看条件类型的求值逻辑,会发现这样一段代码:注释是ReturnunionoftrueTypeandfalseTypefor'any'sinceitmatchesanything,即returnUniontypeoftrueType和falseType,因为any匹配任何类型。原因没说出来吗?(不得不说TS源码里的注释写得真好)然后就是最后一个类型,当条件类型+never:typeTest=Textendstrue?1:2;输入res=Test;为什么永远不会直接返回?debug会发现never也去了mapType的分支:这是什么情况,never不是联合类型,怎么分呢。别人的条件写Union或Never是真的:说明Never已经被特殊对待了。别着急,我们继续往下看。继续往下走,会发现Union和Never在这里分叉了:那么mapType中的never类型直接返回的就是这个类型,也就是never:这就是为什么结果既不是trueType也不是falseType,而是never的原因。至此,我们已经通过源码验证了上述原因的真实性。综上所述,TypeScript的类型系统有一些特殊的设计:当条件类型checkType(左边的类型)为类型参数时,会具有分布式的性质,即传入联合类型时,每个类型都会单独传入计算。最后将结果合并返回。这称为分布式条件类型。另外,如果条件类型遇到never,则直接返回never,遇到any,则返回trueType和falseType的联合类型。此外,boolean也是一个联合类型,这是true|错误的。像这样特别的地方还有不少,我总结在了小册子《TypeScript 类型体操通关秘籍》里,会全面系统的讲TypeScript类型编程,教大家如何用TypeScript源码来讲解这些类型的原理。有兴趣的可以看看,保证不作弊。而且现在买很便宜,才17元。