当前位置: 首页 > 科技观察

【Typescript类型检查原理】类型守卫是如何实现的

时间:2023-03-12 19:47:37 科技观察

本文转载自微信公众号《神光的编程秘籍》,作者神说,必有光zxg。转载本文请联系神光编程秘籍公众号。这一节,我们来说说类型保护的实现原理。由于内容较多,分为两部分。第一部分讲实现思路,第二部分讲代码实现。什么是类型守卫javascript的类型代表了一种可能性,表示可能占用的内存大小,可能调用的方法等等。typescript的类型包含了javascript的类型,可以对类型做交集、并集、各种推导,最终生成准确的类型。typescript的类型推导也是一种可能的推导,目的是为了获得对具体变量类型更准确的描述。准确性意味着减少某些类型的可能性。所有类型编程的目的都是为了产生更小更精确的类型,类型保护也是为了这个目的。类型推导是让整个类型更小更准确,而类型守卫是在类型进入某个分支时暂时变得更小更准确,让类型检查更准确。比如下面的代码中,整体类型是string|number,是一个联合类型。当a进入if分支的时候,显然type只是string,其他情况是不能进入的。这时候可以做进一步的类型缩减。这些被称为类型保护。functionfunc(a:string|number):string{if(typeofa==='string'){returna.toLocaleLowerCase();}else{returna.toFixed(1);}}类型保护的目的是使总体类型在某些条件下暂时变得更小和更精确。此类条件包括typeof、instanceOf、in、===、!==、==、!=。为什么在这些条件下可以缩小类型?因为有可能进入这些分支,那么这个变量就只能是另外一种类型,那么类型的可能性自然就可以进一步缩小。比如in操作符触发的类型守卫:===判断触发的类型守卫:instanceof等也是一样,只要进入一个可以判断具体类型的分支,类型就可以了减少。在ts4.3中,还支持泛型类型缩小(之前只能通过类型断言来缩小类型)。类型缩小是一种自动类型断言。当有时类型缩小或类型推导不起作用时,用作手动类型断言。实现思路分析我们知道,类型归约是在进入条件分支时,暂时减少用于类型检查的类型,所以实现上自然是在检查if和switch的分支时,对类型做一些处理。ts的类型检查是先通过解析配置文件的includes、excludes、files等,结合lib、types、typeRoots的配置,确定所有需要检查的文件,然后递归进行类型检查依次在每个文件上。在检查if和switch节点时,我们只需要判断测试部分是否为BinaryExpression,运算符是in,===,!==,instanceOf等。根据不同的运算符做不同的判断:in:判断是否left是right变量类型的一个属性,如果是,缩小类型instanceof:判断left类型是否是right变量类型的子类型,如果是,缩小类型===/!==:有两种类型:typeofinclude和typeofnotinclude:typeofnotinclude:判断左右是否相等,如果相等则缩小类型为具体字面量类型。包含typeof:如果两边有一个是typeofUnaryExpression,就取type然后比较。如果是这样,请将类型缩小为特定类型。总结打字稿高级类型推导的目的是为了缩小可能性范围,让类型更精确。有时,在进入某些分支时,确定了类型。这时候可以暂时缩小类型的范围。这称为类型保护。触发条件包括in、instanceof、typeof、===、!==等,可以让类型判断更准确。类型保护相当于自动类型断言。当类型保护失败时,手动使用类型断言来缩小类型。我们梳理了实现类型保护的思路,即在遇到条件语句IfStatement和SwitchStatement时,对测试部分进行判断。如果包含in、instanceof、typeof等,则做相应的类型处理,然后进行类型检查。