Kodokon kodokon.com

type 与 interface:extends 与交叉类型

选择正确的构造来建模和组合你的对象类型,而无需重复编写代码。

8 分钟 · 3 题

在 Kodokon 中打开本课

你已经知道如何声明对象类型。在项目中真正的问题在于如何在 typeinterface 之间做选择,然后在不重复编写代码的前提下组合已有的类型。让我们从最常见的场景开始:为长得很像的实体建模。

TYPESCRIPT
interface User {
  id: number;
  name: string;
}

interface Admin extends User {
  permissions: string[];
}

const admin: Admin = {
  id: 1,
  name: "Ada",
  permissions: ["users:write"],
};
用 extends 扩展一个 interface

extends 建立了一种清晰的关系:Admin 就是拥有额外权限的 User。使用 type 别名时,你可以通过交叉运算符 & 得到同样的结果,它会把多个形状合并为一个。对于横切关注点来说,这是完美的工具,比如所有实体上都有的时间戳。

TYPESCRIPT
type Timestamps = {
  createdAt: Date;
  updatedAt: Date;
};

type Product = {
  id: number;
  label: string;
};

type StoredProduct = Product & Timestamps;
用 & 交叉运算符组合类型

那么到底该选哪一个?有两个差异真正重要。第一,只有 type 才能给形如 'active' | 'archived' 的联合类型命名。第二,两个同名的 interface 声明会自动合并:这在扩充某个库的类型时很方便,但在意外发生时却很危险。

TYPESCRIPT
type Status = "active" | "archived";

interface Config {
  locale: string;
}

interface Config {
  debug: boolean;
}

const config: Config = { locale: "fr", debug: true };
联合类型只能用 type,而 interface 声明会合并

知识检测

确认你已牢记本课的重点内容。

  1. 你需要给类型 'draft' | 'published' 命名。必须使用哪个构造?
    • interface
    • type
    • 两者都可以
    • enum
  2. 两个 interface Config { ... } 声明处于同一个作用域中,会发生什么?
    • 立即产生编译错误
    • 第二个覆盖第一个
    • 它们合并成一个 interface
    • 第一个优先生效
  3. 哪个运算符能把两个对象类型别名合并成一个同时要求两者所有属性的类型?
    • |
    • &
    • extends