Skip to content

联合类型(Union Types)

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

正如联合类型的符号是|,它代表了按位或,即只需要符合联合类型中的一个类型,既可以认为实现了这个联合类型,如A | B,只需要实现 A 或 B 即可。 语法: Type1 | Type2 | ... | TypeN

Union Types 常用于函数参数或返回值的类型定义。

typescript
type Width = number | string;
let width: Width = 100; // 正确
width = "100px"; // 正确

function getLength(arg: number | string) {
  // 在函数内部需要使用类型守卫来缩小类型
  if (typeof arg === "number") {
    return arg.toString().length;
  } else {
    return arg.length;
  }
}

交叉类型(Intersection Types)

交叉类型使用 & 运算符,表示将多个类型合并为一个类型。新的类型将具有所有类型的特性。

语法: Type1 & Type2 & ... & TypeN

代表着按位与的 & 表示需要符合这里的所有类型,才可以说实现了这个交叉类型,即 A & B,需要同时满足 A 与 B 两个类型;交叉类型常用于组合现有的对象类型,从而创建新的对象类型。

typescript
interface Colorful {
  color: string;
}

interface Circle {
  radius: number;
}

type ColorfulCircle = Colorful & Circle;

let cc: ColorfulCircle = {
  color: "red",
  radius: 42,
};
typescript
type PartialPointX = { x: number };
type Point = PartialPointX & { y: number };

let point: Point = {
  x: 1,
  y: 1,
};

基本用法

typescript
interface NameStruct {
  name: string;
}

interface AgeStruct {
  age: number;
}

type ProfileStruct = NameStruct & AgeStruct;

const profile: ProfileStruct = {
  name: "yyds",
  age: 18,
};

ProfileStruct 其实就是一个新的,同时包含 NameStruct 和 AgeStruct 两个接口所有属性的类型。

对于原生类型:

typescript
type StrAndNum = string & number; // never

新的类型会同时符合交叉类型的所有成员,存在既是 string 又是 number 的类型吗?当然不。实际上,这也是 never 这一 BottomType 的实际意义之一,描述根本不存在的类型嘛。

同名基础类型属性合并

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

interface Y {
  c: number;
  e: string;
}

type XY = X & Y;
type YX = Y & X;

let p: XY;
let q: YX;
p = { c: 6, d: "d", e: "e" }; // Error
q = { c: "c", d: "d", e: "e" }; // Error
// interface中有同名属性c ; &表示合并
// 表示c既可以是string 又是 number,明显这种类型不存在,所以c最后类型是never了

同名对象类型属性合并

对于对象类型的交叉类型,其内部的同名属性类型同样会按照交叉类型进行合并:

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

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

// 同名的x属性是一个非基本数据类型,可以成功合并
type ABC = A & B & C;

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

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

other eg. 两个联合类型组成的交叉类型, => 两边联合类型的交集:

typescript
type UnionIntersection1 = (1 | 2 | 3) & (1 | 2); // 1 | 2
type UnionIntersection2 = (string | number | symbol) & string; // string

总结一下交叉类型和联合类型的区别就是,联合类型只需要符合成员之一即可(||),而交叉类型需要严格符合每一位成员(&&)。