【TypeScript】TS类型守卫(六)_ts 类型守卫
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
🐱个人主页不叫猫先生
🙋♂️作者简介前端领域新星创作者、华为云享专家、阿里云专家博主专注于前端各领域技术共同学习共同进步一起加油呀
💫系列专栏vue3从入门到精通、TypeScript从入门到实践
📝个人签名不破不立
📢资料领取前端进阶资料以及文中源码可以找我免费领取文末有我wx
目录
专栏介绍
TypeScript从入门到实践专栏是博主在学习和工作过程中的总结实用性非常强欢迎订阅哦学会TS不迷路。
TS系列 | 标题 |
---|---|
基础篇 | TS入门一 |
基础篇 | TS类型声明二 |
基础篇 | TS接口类型三 |
基础篇 | TS交叉类型&联合类型四 |
基础篇 | TS类型断言五 |
基础篇 | TS类型守卫六 |
进阶篇 | TS函数重载七 |
进阶篇 | TS泛型八 |
进阶篇 | TS装饰器九 |
类型守卫
在前几篇介绍了断言在使用断言时我们已经确定了变量的类型确定该类型时一定存在否则则会欺骗编译运行时报错那么为什么还要类型守卫呢因为类型断言还是需要借助类型守卫的类型守卫主要是用来判断未知类型是不是所需要的类型。
类型守卫主要包括四种方式
- in
- typeof
- instanceof
- 自定义类型
1、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属性所以走了第二个判断
2、typeof-类型分类场景下的身份确认
为什么用typeof做类型守卫呢因为typeof能判断JS基本数据类型。typeof只能识别以下类型
- Boolean
- String
- Undefined
- Function
- Number
- Bigint
- Symbol
写法typeof a
a是变量基本数据类型
奇怪为什么typeof
不能识别null
呢
let a= null
typeof a;//object
null
是一个只有一个值的特殊类型表示一个空对象引用可以用来清空对象它是object
类型是历史遗留下来的问题曾提议改为null
类型被拒绝了。
typeof
识别其他的类型比如数组正则等都是object
类型
let a =[1]
typeof a;//Object
var 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)
}
}
3、instanceof-类型分类场景下的身份确认
为什么用instanceof
呢因为typeof
有局限性引用类型比如数组正则等无法精确识别是哪一个种型instanceof
能够识别变量比如实例对象是否属于这个类。instanceof
不能检测原始值类型的值但是原始值对应的对象格式实例则可以检测。具体instanceof
是怎么做类型守卫的呢?
- 写法
a instanceof b
a是参数b是一般都是接口类型。
interface Teacher{
name:string;
courses:string;
}
interface 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)
}
}
4、自定义类型
TS中有一个关键字is
可以判断变量是否属于某种类型。
- 写法
a is b
意思是a是b类型a是函数参数也可以是this
关键字this
关键字一般用在累中判断b可以是接口类型b也可以是number
、string
等其他合法的TS类型。这种写法称作类型谓词使用类型谓词的函数称为类型谓词函数该函数的返回值必须的boolean类型。 - 使用先定义一个变量该变量表示是否是某种类型比如以下定义了
isTeacher
代表了参数cls
是Teacher
类型然后用这个变量来判断。
1函数参数形式
函数中的参数类型为多个类型通过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;
}
}
2this形式
下面代码中的 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
}
}