【Typescript】Typescript交叉类型和联合类型 (12)

交叉类型

将多个类型合并为一个类型,新的类型将具有所有类型的特性,所以交叉类型是所有类型的并集。

// 交叉类型是所有类型的并集
interface IPerson {
    id: string;
    age: number;
  }
  
  interface IWorker {
    companyId: string;
  }
  
  type IStaff = IPerson & IWorker;
  
  const staff: IStaff = {
    id: 'E1006',  age: 33,
    companyId: 'EXE'
  };
  
  console.dir(staff)
interface DogInterface {
    run(): void;
}
interface CatInterface {
    jump(): void;
}
let pet: DogInterface & CatInterface = { 
    run() {},
    jump() {},
};

联合类型

声明的类型并不确定,可以为多个类型中的一个。所以联合类型取所有类型中的交集。

字面量联合类型

let a: number | string = 'a'; 
let b: 'a' | 'b' | 'c'; // 字面量联合类型
let c: 1 | 2 | 3; // 字面量联合类型

对象联合类型

class Dog implements DogInterface {
    run() {}
    eat() {}
}
class Cat implements CatInterface {
    jump() {}
    eat() {}
}
enum Master { Boy, Girl };
function getPet(master: Master) {
    // pet类型被推断为Dog和Cat的联合类型
    let pet = master === Master.Boy ? new Dog() : new Cat(); 
    // 如果一个对象是联合类型,在类型未确定的情况下,只能访问所有类型的共有成员(取所有类型的交集)
    pet.eat(); 
    // pet.run(); 这个方法是不能使用的
    return pet;
}

可区分的联合类型

本质上讲,是一种结合了联合类型和字面量类型的一种类型保护方法。
一个类型如果是多个类型的联合类型,并且每个类型之间有一个公共的属性,那么我们就可以凭借这个公共属性创建不同的类型保护区块。

interface Square {
    kind: 'square';
    size: number;
}
interface Rectangle {
    kind: 'rectangle';
    width: number;
    height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
    switch (s.kind) {
        case 'square':
            return s.size * s.size;
        case 'rectangle':
            return s.height * s.width;
    }
}

这些代码不去升级没有问题,但如果加一种新的类型,就会出现隐患。

解决办法:
1、给函数指定一个明确的返回值类型,此时ts会判断所有的switch分支是不是包含了所有的情况。
2、利用never类型

interface Square {
    kind: 'square';
    size: number;
}
interface Rectangle {
    kind: 'rectangle';
    width: number;
    height: number;
}
interface Circle {
    kind: 'circle',
    r: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
// function area(s: Shape): number { // 1) 给函数指定一个明确的返回值类型,此时ts会判断所有的switch分支是不是包含了所有的情况
    switch (s.kind) {
        case 'square':
            return s.size * s.size;
        case 'rectangle':
            return s.height * s.width;
        case 'circle':
            return Math.PI * s.r;
        default: // 2) 
            return ((e: never) => { throw new Error(e); })(s); // 该函数的作用是检查s是否是never类型。若s是never类型,表示前面的分支都覆盖了,则default分支永远不会执行到;
    }
}
console.log(area({kind: 'circle', r: 1}));
posted @ 2021-03-27 08:21  攀登高山  阅读(238)  评论(0)    收藏  举报