这是你所知道的ts类型断言和类型守卫吗?

250 阅读5分钟

我们知道,ts是强类型语言,如果想要有更好的语法提示和类型检测,我们就需要缩小变量的类型范围。下面这些方法可以帮助我们缩小变量范围。

类型断言,类型转换

就是通过as关键字来将变量强制推断为某种类型。就是绕过ts编译检查,类型断言就是对编译器说:我就是这个类型,无需检查。注意这种转换变量类型和转换的类型必须有重叠的类型,否则是不被允许的

function foo(a: number | string) {
  a = (a as number) + 1 // 将a强制推断为number类型
  return a
}

console.log(foo("2")) // “21”

还有就是如果项目中有些类型编译时报错,我们可以强制断言成any类型。(在开发中在座的各位是不是都是这么干的。🫣)

let symid = Symbol()
const user = {
  [symid]: 1,
  username: "zh"
}

let username = "username"
console.log("username:", user[username as any]) // zh

类型转换和类型断言有相同的作用,就是将当前变量强制推断为某个类型,而不让编译器在进行检测。注意这种转换变量类型和转换的类型必须有重叠的类型,否则是不被允许的

// const num = <number>"3" // error
const num = <number><any>"3" // 字符串和数字类型没有重叠部分,所以需要先将string转为any或者unknown才可以转为number

类型守卫

在语句的块级作用域(if语句内或条目运算符表达式内)缩小变量的一种类型推断的行为。

TS 条件语句中遇到下列条件关键字时,会在语句的块级作用域内缩小变量的类型,这种类型推断的行为称作类型守卫(Type Guard)。类型守卫可以帮助我们在块级作用域中获得更为需要的精确变量类型。

  • 实例判断:instanceof
  • 属性或者方法判断:in
  • 类型判断:typeof
  • 字面量相等判断:==, ===, !==, !=

instanceof

这个一般用在类中,类似于其他面向对象语言中的多态。例如在方法接收一个父类类型的变量时,我们在方法体中可以通过instanceof来缩小该两边的类型范围,让我们可以有更好的语法提示等等。


class Person {
  constructor(public name: string, public age: number) {

  }

  say() {

  }
}

class Child extends Person {
  constructor(public name: string, public age: number, public playName: number) {
    super(name, age)
  }

  play() {

  }
}

class Dog extends Person {
  constructor(public name: string, public age: number, public sleepName: number) {
    super(name, age)
  }

  sleep() {

  }
}

class Customer {
  constructor(public name: string) {
  }

  buy(object: Person) {
    if(object instanceof Child) { // Child
      object.play()
    }else if(object instanceof Dog){ // Dog
      object.sleep()
    }
  }
}

in

主要是通过判断该对象中是否有指定属性和方法,来确定对象的类型。

class Customer {
  constructor(public name: string) {
  }

  buy(object: Person) { // 这里定义父类类型,使用in操作符并不能推断出具体的类型
    if("play" in object) {
      object.play() // error
    }else if("sleep" in object){
      object.sleep() // error
    }
  }
  
  buy(object: Child | Dog) { // 这里的object类型还不能直接写成Person,否则 in 操作符不能正确推断
    if("play" in object) {
      object.play()
    }else if("sleep" in object){
      object.sleep()
    }
  }
}

typeof

他主要就是来缩小一些联合的基本数据类型变量的类型范围了。

function bar(a: number | string) {
  if(typeof a === "number") {
    a.toFixed()
  }else {
    a.replace("", "")
  }
}

自定义守卫

如果我们代码中有多处都需要缩小变量类型,我们就可以自定义一个守卫供我们使用,来简化代码。

function 函数名(形参: 参数类型,大多为any): 形参 is A类型 {
    return true / false
}

如果我们不使用自定义守卫,而是单独封装一个方法用于判断,那么ts只是把它当做一个boolean,并不会缩小变量类型范围。

class Customer {
  constructor(public name: string) {
  }

  buy(object: Person) {
    if(isChild(object)) { // 这里只会被看作是一个boolean,并不会将object看做为Child类型
      object.play() // error
    }
  }
}


function isChild(object: Person): boolean {
  return object instanceof Child
}

所以我们可以使用自定义守卫。

class Customer {
  constructor(public name: string) {
  }
  
  buy(object: Person) {
    if(isChild(object)) {
      object.play()
    }
  }
}

// function isChild(object: Person): boolean {
//   return object instanceof Child
// }

function isChild(object: Person) { // 这里不指定返回值类型,他也会推断出为 object is Child
  return object instanceof Child
}

往期年度总结

往期文章

专栏文章

结语

本篇文章到此就结束了,欢迎在评论区交流。

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏✍️评论,   支持一下博主~