淘先锋技术网

首页 1 2 3 4 5 6 7

🐱个人主页:不叫猫先生
🙋‍♂️作者简介:前端领域优质创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!
💫系列专栏: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 | Bfunction 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也可以是numberstring等其他合法的TS类型。这种写法称作类型谓词,使用类型谓词的函数称为类型谓词函数,该函数的返回值必须的boolean类型。
  • 使用:先定义一个变量,该变量表示是否是某种类型,比如以下定义了isTeacher,代表了参数clsTeacher类型,然后用这个变量来判断。

(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;
    }
}

(2)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
    }
}