TypeScript最佳实践(三)交叉类型、联合类型

66 阅读3分钟

1. 交叉类型&

交叉类型是将多个类型合并为一个类型。这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如,Person & Serializable & Loggable同时是 Person 和Serializable 和Loggable

1. 同名基础类型属性的合并

注意:

interface X {
    c: string;
    d: string;
}

interface Y {
    c: number;
    e: string
}

type XY = X & Y;

上面代码X与Y中都有一个c属性,那么XY中c的类型为string & number = nerver,而不是string | number

2. 同名非基础类型属性的合并

interface D { d: boolean; }
interface E { e: string; }
interface F { f: number; }

interface A { x: D; }
interface B { x: E; }
interface C { x: F; }

type ABC = A & B & C;

let abc: ABC = {
    x: {
        d: true,
        e: 'semlinker',
        f: 666
    }
};

console.log('abc:', abc);

这里其实ABC类型为{ x: D & E & F }

3. never

任意类型与 never 交叉都得到 never

type Tnumber = number & never;
// never

type Tstring = string & never;
// never

2. 联合类型 |

联合类型表示一个值可以是几种类型之一。 我们用竖线( |)分隔每个类型,所以 number | string | boolean表示一个值可以是 number, string,或 boolean

1. 多个接口联合

如果一个值是联合类型,我们只能访问此联合类型的所有类型里共有的成员。

interface Bird { 
    fly(); 
    layEggs(); 
} 
interface Fish { 
    swim(); 
    layEggs(); 
} 

function getSmallPet(): Fish | Bird { 
    // ... 
} 
let pet = getSmallPet(); 
pet.layEggs(); // okay 
pet.swim(); // errors

2. 联合类型的类型守卫

enum CarTransmission {
    Automatic = 200,
    Manual = 300
}
interface Motorcycle {
    vType: "motorcycle"; // discriminant
    make: number; // year
}

interface Car {
    vType: "car"; // discriminant
    transmission: CarTransmission
}

interface Truck {
    vType: "truck"; // discriminant
    capacity: number; // in tons
}

type Vehicle = Motorcycle | Car | Truck;

function evaluatePrice(vehicle: Vehicle) {
    if(vechile instanceof Car) {
        return vehicle.transmission * EVALUATION_FACTOR;
    }
    if(vechile instanceof Truck) {
        return vehicle.capacity * EVALUATION_FACTOR;
    }
    if(vechile instanceof Motorcycle) {
        return vehicle.make * EVALUATION_FACTOR;
    }
}

3. never

任意类型与 never 联合都不受 never 影响

type Tnumber = number | never; // number

type Tstring = string | never; // string

3. 区别

赋值区别

对于对象类型合成的交叉类型是多个类型属性和方法的合并后的类型,属于多个类型的并集,必须是两个类型的全部属性和方法才能赋值给交叉类型变量。【可选属性和方法除外】

对于对象类型合成的联合类型变量可以接受联合类型中任意一种数据类型全部属性和方法,也可以是两个类型的全部属性和全部方法【可选属性和方法除外】,也可以是一种数据类型全部属性和方法+其他类型的某个属性和某个方法。

获取属性和方法区别:

交叉类型变量可以获取两个类型的任意属性和任意方法,而联合类型的变量只能获取两个类型的共同属性和方法【交集属性和交集方法】

type objtype1 = { username: string, age: number }
type objtype2 = { custname: string, phone: number, age: number }
type objtype3 = { address: string }

// 定义:将多个类型合并【多个类型属性和方法的并集】成的类型就是交叉类型。
let jiaochatype: objtype1 & objtype2 & objtype3 = {
  username: "wangwu", age: 23, custname: "lisi", phone: 111, address: "shanghai"
}
// `jiaochatype.`可以提示出来objtype1 & objtype2 & objtype3中的所有属性

let uniontype: objtype1 | objtype2 = {
  username: "wangwu", age: 23, custname: "lisi", phone: 111
}
// `uniontype.`只能提示出来objtype1 | objtype2中共有的属性