【TypeScript】TS类型守卫(六)
- 【TypeScript】TS类型守卫(六)
- 一、什么是类型守卫
- 二、in操作符
- 三、typeof操作符
- 四、instanceof操作符
- 五、自定义类型谓词函数
一、什么是类型守卫
TypeScript类型守卫(Type Guards) 是一种用于在代码中确定变量类型的技术,它允许我们在运行时检查变量的类型,并根据需要执行不同的逻辑。TypeScript 类型守卫可以使用不同的语法实现,如 typeof操作符、instanceof操作符、in操作符和自定义类型谓词函数。它们可用于增强类型安全性,并提高代码的可读性和可维护性。
在上篇介绍了断言(不清楚的小伙伴点击该链接查看,【TypeScript】类型断言-类型的声明和转换(五))在使用断言时我们已经确定了变量的类型,确定该类型时一定存在(否则则会欺骗编译,运行时报错),那么为什么还要类型守卫呢?因为类型断言还是需要借助类型守卫的,类型守卫主要是用来判断未知类型是不是所需要的类型。
主要的四种类型守卫:
- typeof操作符
- instanceof操作符
- in操作符
- 自定义类型谓词函数
二、in操作符
-
定义属性场景下内容的确认
先写两个接口Teacher、Student,然后将这两个接口进行联合声明,使用
in
来判断属性是否在传递的参数中,然后分别作输出。
缺点:用in
关键字缩小数据类型必须有一个独特的属性作为判别标准,否则不能用in
关键字
interface Teacher{name:string;courses:string;
}
interface Student{name:string;study:string;
}
type Class = Teacher | Student;
function getInfo(val:Class){//此时val类型缩小为Teacher类型if('courses' in val){console.log(val.courses)}//此时val类型缩小为Student类型if('study' in val){console.log(val.study)}
}
getInfo({ name: 'student', study: "Philosophy" });
//打印结果为Philosophy,因为传参中含有study属性,所以走了第二个判断
三、typeof操作符
类型分类场景下的身份确认
为什么用 typeof
做类型守卫呢?因为 typeof
能判断JS基本数据类型。
typeof只能识别以下类型:
- Boolean
- String
- Undefined
- Function
- Number
- Bigint
- Symbol
语法:typeof a
其中a
是变量(基本数据类型)
需要注意的是,对于 null
类型,使用 typeof
判断时,得到的结果是 object
。
typeof
识别其他的类型比如 数组,正则等都是object
类型
let a =[1]
typeof a;//Objectvar reg = RegExp("a","i");
typeof reg//reg
typeof
怎么起到守卫的作用呢,是通过 typeof
判断变量类型然后执行相应的逻辑,具体如下:
function class(name: string, score: string | number) {//识别到sore为number类型if (typeof score === "number") {return "teacher:" + name + ":" + score;}//识别到sore为string类型if (typeof score === "string") {return "student:" + name + ":" + score;}
}
上面案例的传参都是基本类型,当传一个对象时候,我们也可以用对象中的属性来进行判断,比如:
interface A{a:string;
}
interface B{a:number;
}
type Class = A | B;
function getInfo(val:Class){//判断val的属性a的类型为number类型if(typeof val.a === "number"){console.log('B:'+ val.a)}//判断val的属性a的类型为string类型if(typeof val.a === "string"){console.log('A' + val.a)}
}
编译后的结果如下:
四、instanceof操作符
为什么用instanceof
呢?因为 typeof
有局限性,引用类型比如数组、正则等无法精确识别是哪一个种型,instanceof
则能够识别变量(比如实例对象)是否属于这个类。instanceof
不能检测原始值类型的值,但是原始值对应的对象格式实例则可以检测。
具体 instanceof
是怎么做类型守卫的呢?
语法:a instanceof b
其中 a
是参数,b
一般都是接口类型。
abstract class Teacher{name:string;courses:string;}
abstract class Student{name:string;study:string;}type Class = Teacher | Student;function getInfo(val:Class){//判断val的类型是否是定义的接口Teacher类型if(val instanceof Teacher){console.log('teacher:'+ val.courses)}//判断val的类型是否是定义的接口Student类型if(val instanceof Student){console.log('student' + val.study)}}
五、自定义类型谓词函数
TypeScript 中有一个关键字 is
可以判断变量是否属于某种类型。
语法:a is b
,意思是 a是b类型,a
可以是函数参数,也可以是this关键字,this关键字一般用在类中判断,b
可以是接口类型,b
也可以是number、string等其他合法的 TypeScript 类型。
这种写法称作类型谓词,使用类型谓词的函数称为 类型谓词函数,该函数的返回值必须的boolean类型。
使用:先定义一个变量,该变量表示是否是某种类型,比如以下定义了 isTeacher
,代表了参数 cls 是 Teacher 类型,然后用这个变量来判断。
-
函数参数形式
函数中的参数类型为多个类型,通过
is
关键字自定义类型,将函数参数精确到某种类型,然后再执行相应的逻辑。interface Teacher{name:string;courses:string; } interface Student{name:string;study:string; } const isTeacher = function (cls: Teacher | Student): cls is Teacher {return 'courses' in cls; } const getName = (cls: Teacher | Student) => {if(isTeacher(cls)) {return cls.courses;}return null; }
编译后如下:
-
this形式
下面代码中的 User 是抽象类,不能被实例化,Staff 和 Student 都继承自 User。实例方法 isStaff 用于将类型收窄为 Staff,实例方法 isStudent 用于将类型收窄为 Student。
abstract class User {name: string;constructor(name: string) {this.name = name;}isStudent(): this is Student {return this instanceof Student;}isStaff(): this is Staff {return this instanceof Staff; }
}class Student extends User{study: string;constructor(name: string, study: string) {super(name)this.study = study}
}class Staff extends User {workingYears: number;constructor(name: string, workingYears: number) {super(name)this.workingYears = workingYears}
}function judgeClassType(obj: User) {if (obj.isStaff()) {// obj的类型被缩小为 Staff} else if (obj.isStudent()){// obj 的类型被缩小为 Student}
}
以上就是【TypeScript】TS类型守卫的介绍。