ts学习心得: 联合类型与类型保护

129 阅读2分钟

本文是ts系列其中一篇,是总结自己在学习和工作中使用ts的心得感想,仅作为自己复习使用,如对您有启发不胜荣幸。

类型保护

首先看下面这一段代码:

interface Bird {
  fly: boolean
  sing: () => {}
}

interface Dog {
  fly: boolean
  bark: () => {}
}

function trainAnimal(animal: Bird | Dog) {
  animal.sing() // 提示错误
}

当我访问参数 animal 的时候,提示属性有哪些?答案是fly,没有sing或者bark。

像这种通过联合类型定义的一个变量,当我们访问这个变量的时候,只会提示公共的属性和方法。如果你这个时候直接访问animal.sing(),就会报错,避免这种报错就叫类型保护

我们可以通过什么方式来做类型保护呢?

类型断言 as

function trainAnimal(animal: Bird | Dog) {
  if (animal.fly) {
      ;(animal as Bird).sing()
  } else {
      ;(animal as Dog).bark()
  }
}

sameValue 现在是 any 类型,但是我知道它其实是个字符串类型,那么就需要强制转换

let sameValue: any = 'this is a string' 
let strLength: number = (<string>sameValue).length
// 推荐使用这种语法
let strLength: number = (sameValue as string).length 

只有联合类型才会出现需要类型保护的情况

in 语法

function trainAnimal1(animal: Bird | Dog) {
  if ('sing' in animal) {
      animal.sing()
  } else {
      animal.bark()
  }
}

在 TypeScript 中,in 关键字主要有两种用法:一种是在类型上下文中(作为类型保护或映射类型的一部分),另一种是在运行时(检查对象中是否存在某个属性)。

在 JavaScript/TypeScript 的运行时环境中,in 操作符用于检查一个对象或其原型链上是否存在指定的属性。

const car = { make: 'Toyota', model: 'Camry' };
console.log('make' in car); // true
console.log('year' in car); // false
/ 继承的属性也会返回 true
console.log('toString' in car); // true, 因为从 Object.prototype 继承```

`Object.prototype.hasOwnProperty` 只检查对象自身的属性(不包括原型链)。

在 TypeScript 的类型系统中,in 关键字主要用于两个地方:类型保护(Type Guards)和映射类型(Mapped Types)。

在类型保护中,in 操作符可以用于缩小变量的类型范围。通过检查某个属性是否存在,TypeScript 可以推断出更具体的类型。如上面的例子。

在映射类型中,in 用于遍历联合类型中的每一个类型(通常是字符串字面量联合类型),从而创建一个新的类型。语法:

type Optional<T> = {
  [P in keyof T]?: T[P];
};

interface Person {
  name: string;
  age: number;
}

typeof

function add(first: string | number, second: string | number) {
  if (typeof first === 'string' || typeof second === 'string') {
      return `${first}${second}`
  } else {
      return first + second
  }
}

instanceof

instanceof 操作符是 JS 中的原生操作符,用来判断一个实例是不是某个构造函数创建的,或者是不是使用 es6 语法的某个类创建的。在 ts 中,使用 instanceof 操作符可以达到类型保护的效果。

class Fish {
  swim() {
      console.log('swim')
  }
  eat() {}
}

class Mouse {
  miao() {
      console.log('miao')
  }
  eat(){}
}

function getRandPet () : Fish | Mouse {
  return Math.random() > 0.5 ? new Fish() : new Mouse() 
}

const petName = getRandPet()
if (petName instanceof Fish) {
  petName.swim()
} 
if (petName instanceof Mouse) {
  petName.miao()
}