TypeScript 联合类型和类型保护

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

interface Dog{
  fly: boolean,
  bark: ()=>{}
}
/**
 * animal: Bird | Dog这就是一个联合类型
 * animal 既可以是 Bird 又可以是 Dog
 * 联合类型只提示公共的属性
 */
 // 第一种类型保护方案:类型断言的方式
function trainAnimal(animal: Bird | Dog) {
  /**
   * 这里直接调用 animal.sing() 是会报错的,因为 Dog 不存在 sing()
   * 解决这个问题第一种方案:断言
   */
  if (animal.fly) {
    (animal as Bird).sing(); // 强制告诉 TS,animal 是 Bird 类型
  }
  (animal as Dog).bark();
  
}


// 第二种类型保护方案:in 语法来做类型保护
function trainAnimal2(animal: Bird | Dog) {
  if ('sing' in animal) { // 告诉 ts animal 里面有 sing
    animal.sing();
  } else { // 上面 animal 有sing, else 就是没有 sing, ts 可以推断出来
    animal.bark();
  }
}


// 第三种类型保护方案: typeof 语法来做类型保护
function add(first: string | number, second: string | number) {
  /**
   * 这里直接 first + second 也会报错,因为有可能他们是 string 类型
   * 这个时候也可以用类型保护
   */
  if (typeof first === 'string' || typeof second === 'string') {
    return `${first}${second}`;
  }
  return first + second
}


// 第四种类型保护方案: instanceof 语法来做类型保护
class NumberObj { // 因为只有 class 才能用 instanceof 做类型保护
  count: number
}
function addSecond(first: object | NumberObj, second: object | NumberObj) {
    /**
    * 这里直接 first.count + second.count 也会报错,因为有可能他们是 object,没有 count 属性
    * 这个时候也可以用类型保护
    */
  if (first instanceof NumberObj && second instanceof NumberObj) {
    return first.count + second.count;
  }
  return 0;
}

总结:类型保护四种方式

1、类型断言的方式  animal as Bird

2、in 语法来做类型保护  if ('sing' in animal){}

3、 typeof 语法来做类型保护  if (typeof first === 'string' || typeof second === 'string') {}

4、instanceof 语法来做类型保护 if (first instanceof NumberObj && second instanceof NumberObj) {}