Kodokon kodokon.com

枚举与 const 断言:现代的替代方案

理解枚举的局限,并用 as const 从被冻结的常量中派生出你的类型。

7 分钟 · 3 题

在 Kodokon 中打开本课

enum 从语言的早期就是其组成部分,你会在很多代码库中遇到它。它把命名常量归到单一的类型下,既可以当作值使用,也可以当作类型注解。

TYPESCRIPT
enum Role {
  User = "USER",
  Admin = "ADMIN",
}

function canDelete(role: Role): boolean {
  return role === Role.Admin;
}
一个经典的字符串枚举

然而现代生态正在远离它。enum 是一种在 JavaScript 中并不存在的语法:编译器会在运行时生成一个对象,这会让某些工具变得复杂,而且它与 erasableSyntaxOnly 选项不兼容。替代方案是:一个用 as const 冻结的普通对象,你从中派生出类型。

TYPESCRIPT
const ROLES = {
  User: "USER",
  Admin: "ADMIN",
} as const;

type Role = (typeof ROLES)[keyof typeof ROLES];

function canDelete(role: Role): boolean {
  return role === ROLES.Admin;
}
带派生类型的 as const 对象,即现代的等价写法

as const 对数组同样有效:每个元素都变成只读的字面量,而 (typeof SIZES)[number] 会产生这些值的联合类型。单一的事实来源同时供给运行的代码和类型。

TYPESCRIPT
const SIZES = ["sm", "md", "lg"] as const;

type Size = (typeof SIZES)[number];

function isSize(value: string): value is Size {
  return (SIZES as readonly string[]).includes(value);
}
一个 as const 数组:运行时可遍历,在类型层面是一个联合

知识检测

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

  1. enum 和用 as const 冻结的对象之间有什么重大区别?
    • enum 是 TypeScript 特有的、会生成代码的语法,而 as const 对象仍然是纯粹的 JavaScript
    • as const 对象在运行时更慢
    • enum 只能包含数字
  2. 把 as const 应用到数组 ['sm', 'md'] 上会产生什么?
    • string[]
    • 一个由字面量类型组成的只读元组
    • 一个类型为 Array<'sm' | 'md'> 的可变数组
    • 一个编译错误
  3. 如何获取一个用 as const 冻结的 ROLES 对象其值的联合?
    • keyof typeof ROLES
    • (typeof ROLES)[keyof typeof ROLES]
    • typeof ROLES