TypeScript 学习笔记(四):类型守卫

这篇具有很好参考价值的文章主要介绍了TypeScript 学习笔记(四):类型守卫。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

类型守卫

  1. 类型守卫的作用在于触发类型缩小。实际上,它还可以用来区分类型集合中的不同成员

  2. 类型守卫包括switch、字面量恒等、typeof、instanceof、in 和自定义类型守卫 简单说当一个类型是多种可能时例如’any’,‘unknown’,‘联合类型’ 等在逻辑判断时候要具体到其唯一子集可能性

  • 2.1.类型判断:typeof
  • 2.2.实例判断:instanceof
  • 2.3.属性判断:in
  • 2.4.字面量相等判断:==, =, !=, !

1. 没有使用类型守卫案例

通过断言,断言其子类型做到缩小范围不报错,虽然这种形式也可以但是需要大量断言来区分类型

const getRandomValue = (list: (string | number)[]) => {
  const randomNumber = Math.random() * 10
  if (randomNumber > 5) return list[0]
  else return list[1]
}

const item = getRandomValue([1, 'w'])
// 直接这些写会报错
// 首先第一个问题是返回值的类型不确定是字符还是数字
// 数字是没有length 属性的所以这么写的判断ts 会报错的
// if(item.length){
//     console.log(item.length)
// }else{
//     console.log(item.toFixed())
// }

// 解决第一种使用类型断言
// 缺点 每一个item 都要使用对应的类型断言
if ((item as string).length) {
  console.log((item as string).length)
} else {
  console.log((item as number).toFixed())
}

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 getType(params: string | number) {
  // return params.length ? params.length : params 这么写会报错  这就是为什么要类型守卫缩小类型
  if (typeof params === 'string') {
    return params.length
  } else {
    return params
  }
}

上面案例的传参都会基本类型,当传一个对象时候,我们也可以用对象中的属性来进行判断,比如:

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. 获取value 值 – 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属性,所以走了第二个判断

注意:用 in 关键字缩小数据类型必须有一个独特的属性作为判别标准,否则不能用 in 关键字

5. 字面量恒等

1.如果是字面量这种联合类型可以使用具体值去比较
2.也可用switch 来缩小类型 代替if

function getType(params: 'a' | 1) {
  if (params === 'a') {
    return params.length
  }
  return params
}
type Foo = {
  kind: 'foo'; // 字面量类型
  foo: number;
};

type Bar = {
  kind: 'bar'; // 字面量类型
  bar: number;
};

function doStuff(arg: Foo | Bar) {
  if (arg.kind === 'foo') {
    console.log(arg.foo); // ok
    console.log(arg.bar); // Error
  } else {
    console.log(arg.foo); // Error
    console.log(arg.bar); // ok
  }
}

6. 自定义守卫 – is

TS中有一个关键字is 可以判断变量是否属于某种类型。

// 1.往往开发时候会吧一些判单同一封装 像下面的例子虽然封装了,但实际效果却报错

function isString(params: unknown) {
  return typeof params === 'string'
}

function getName(params: number | string) {
  // if(typeof params === "string") 可以的但是这种重复逻辑一般会封装
  if (isString(params)) {
    return params.length // 报错
  }  
}

正确写法:
1.这里的is 可以是任意类型,可以是自己定义的接口类型,这里是因为需求是string 类型,如果不做is 类型,
TS 只能推断出 isString 是一个返回布尔值的函数,而并不知道这个布尔值的具体含义’{形参} is {类型} 的语法结构’

function isString(params: unknown) :params is string{
  return typeof params === 'string'
}

function getName(params: number | string) {
  // if(typeof params === "string") 可以的但是这种重复逻辑一般会封装
  if (isString(params)) {
    return params.length 
  }  
}
1. 函数参数形式
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文章来源地址https://www.toymoban.com/news/detail-553216.html

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 学习笔记(四):类型守卫的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript 学习笔记(六):索引签名类型、映射类型

    keyof 可以用于获取某种类型的所有键,其返回类型是联合类型。 keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键 通过例子可以看到,这里的keyof Info其实相当于\\\"name\\\" | “age”。通过和泛型结合使用,TS 就可以检查使用了动态属性名的代码: 接口 基本数据类型 类 如果

    2024年02月17日
    浏览(43)
  • TypeScript 学习笔记(一):基本类型、交叉类型、联合类型、类型断言

    TS中实现对象属性必选、对象属性在开发过程中十分常见,前端在传参数时,有些参数比必传,有些是选传,我们可以定一个多个对象来实现传参,但是这让代码变得冗余。我们可以通过TS定义数据类型来实现。 TypeScript中文网 1. 数组 2. 布尔 3. 数值 当我们给num赋值为123但没有

    2024年02月15日
    浏览(45)
  • TypeScript 学习笔记(二):接口与类型别名、字面量类型

    在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些

    2024年02月16日
    浏览(38)
  • TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型

    JavaScript的变量类型相当于是动态类型,可以跟随着赋值的改变而类型改变,函数的参数也没有设定类型,所以在定位错误以及安全性上不太够。 说明 1.TS不能被JS解析器直接执行,需要编译成JS执行 2.即使TS编译出错也可以编译成JS 1.TypeScript是什么? TypeScript 是类型安全的Ja

    2024年02月16日
    浏览(74)
  • 前端TypeScript学习day02-TS常用类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 TypeScript 常用类型 接口  元组  类型推论 类型断言 字面量类型 枚举 any 类型 typeof  当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到

    2024年02月08日
    浏览(50)
  • 前端TypeScript学习day03-TS高级类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)            目录 TypeScript 高级类型 class 类 class继承  extends implements  类成员可见性  public  protected  private   readonly 兼容性 类型兼容性 接口兼容性  函数兼容性  TypeScri

    2024年02月08日
    浏览(36)
  • 前端TypeScript学习day04-交叉类型与泛型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)            目录 交叉类型 泛型 创建泛型函数 调用泛型函数: 简化调用泛型函数: 泛型约束  指定更加具体的类型 添加约束  泛型接口  泛型类 泛型工具类型  Partial 

    2024年02月08日
    浏览(43)
  • TypeScript学习笔记、鸿蒙开发学习笔记

    struct Index   自定义组件:可复用的UI单元 @Component    自定义组件 @Entry              当前组件是入口组件 @State              标记变量为状态变量,值变化会触发UI刷新  

    2024年02月02日
    浏览(43)
  • 前端TypeScript学习day05-索引签名、映射与类型声明文件

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)              目录 索引签名类型  映射类型 索引查询(访问)类型 基本使用  同时查询多个索引的类型  TypeScript 类型声明文件  概述 TS 的两种文件类型  类型声明文件的

    2024年02月08日
    浏览(47)
  • Typescript学习笔记(1.0)

    typescript是由微软开发的自由和开源的编程语言。 typescript是JavaScript的一个超集,就是说JavaScript的语法typescript全部支持,并且在JavaScript进行了扩充,并在JavaScript的基础上进行了变量、函数、返回值等类型限制。 首先,是安装typescript。因为他需要编译,需要首先安装Node.js。

    2023年04月09日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包