Skip to content
大纲

组合类型

组合类型指的是组合多个类型而产生的新类型, 包括联合类型和交叉类型。

联合类型

联合类型表示一个值可以是几种类型之一, 用竖线 | 分隔每个类型。如 number | string | boolean 代表值可以是 number、string 或 boolean 的任意一种。

ts
type UnionType = string | number | boolean

在联合类型没有确定值真正属于哪种类型之前, 只能访问所有类型里共有的成员。

ts
function test(arg: UnionType) {
  arg.toString() // ✔️
  arg.toFixed() // ❌
}

类型保护

在某些场景下, 需要把"宽"的联合类型, "收窄"到一个具体的类型。

也就是说, 需要一种机制, 能告诉类型系统:『听着, 现在我知道这个东西的具体类型了, 请把圈缩小一些。』而这种机制, 就是类型保护。

typeof 收窄

typeof 类型保护有两种形式能够识别:

  • typeof v === typename
  • typeof v !== typename
ts
function test(params: string | number) {
  if (typeof params === 'string') {
    // params 类型收窄到了 string
    params.toUpperCase() // ✔️
  }
}

instanceof 收窄

instanceof 类型保护是通过构造函数来细化类型的一种方式。其右侧要求是一个构造函数, 此时左侧类型会被收窄到:

  • 构造函数的 prototype 属性的类型
  • 构造函数返回类型构成的联合类型(构造函数存在重载版本时)
ts
interface DateOrRegExp {
  new (): Date
  new (str: string): RegExp
}

let A: DateOrRegExp

function test(params: Date | RegExp | DateOrRegExp) {
  if (params instanceof Date) {
    params.getFullYear() // params: Date
  }
  if (params instanceof A) {
    params // params: RegExp | Date
  }
}

in 语法收窄

in 操作符可以安全的检查一个对象上是否存在一个属性, 也可被作为类型保护使用。

ts
interface Fish {
  swim: () => {}
}
interface Bird {
  fly: () => {}
}
function test(animal: Fish | Bird) {
  if ('swim' in animal) {
    return animal.swim()
  }
  return animal.fly()
}

真值收窄

ts
function test(params?: string) {
  params.toUpperCase() // ❌
  if (params) {
    params.toUpperCase() // ✔️
  }
}

相等收窄

=== 全等运算符也可用于类型保护。

ts
function test(x: string | number, y: string | boolean) {
  if (x === y) {
    x.toUpperCase() // ✔️
  }
}

自定义类型保护

我们也可以自定义一个类型保护, 只需要简单地定义一个函数, 它的返回值是一个 类型谓词:

ts
interface Fish {
  swim: () => {}
}
interface Bird {
  fly: () => {}
}
function isFish(animal: Fish | Bird): animal is Fish {
  return !!(animal as Fish).swim
}
function test(animal: Fish | Bird) {
  if (isFish(animal)) {
    return animal.swim()
  }
  return animal.fly()
}

交叉类型

交叉类型是将多个类型合并为一个类型。这可以把现有的多种类型叠加到一起成为一种类型, 它包含了所需的所有类型的特性。

ts
interface Circle {
  radius: number
}
interface Colorful {
  color: string
}

type ColorfulCircle = Circle & Colorful
// colorfulCircle 必须同时包含 radius 和 color 属性
const colorfulCircle: ColorfulCircle = {
  radius: 1,
  color: 'yellow',
}

Mochi's personal blog.