讲解

枚举(enum)是 TypeScript 独有的语法(JavaScript 里没有对应物),用于给一组命名常量建一个类型。数字枚举从 0 开始自动递增(也可指定起始值),支持反向映射(用值反查名字);字符串枚举每个成员必须显式赋值,没有反向映射,但调试时日志可读性好,实践中字符串枚举远比数字枚举常用。

enum 有一个重要的工程现实:它是 TypeScript 中少数会产生运行时代码的类型特性——编译后会生成一个真实的对象。这带来两个后果:一是打包体积里多了运行时代码;二是在某些只擦除类型的工具链(esbuild 的 isolatedModules 模式、Node 的类型剥离运行)里枚举的某些用法(const enum)会被拒绝。const enum 在编译时直接内联值、不生成对象,体积小但兼容性差,Babel/esbuild 流程下要避免。

因此现代 TypeScript 社区的倾向是:新代码优先考虑「字面量联合 + as const 对象」的组合,它零运行时开销、与纯 JS 心智一致、工具链兼容性最好;老代码里的 enum 继续用没问题。本章两种写法都讲,选型由项目工具链决定。

示例

字符串枚举的基本用法:

enum Role {
  Admin = "ADMIN",
  Editor = "EDITOR",
  Viewer = "VIEWER",
}

function canDelete(role: Role): boolean {
  return role === Role.Admin;
}

const myRole: Role = Role.Editor;
console.log(`${myRole} 能删除吗:${canDelete(myRole)}`);
console.log(`${Role.Admin} 能删除吗:${canDelete(Role.Admin)}`);

数字枚举的自动递增与反向映射:

enum Direction {
  Up = 1,
  Down,
  Left,
  Right,
}

const d: Direction = Direction.Left;
console.log(`Left 的值:${d}`);
console.log(`值 3 的名字:${Direction[3]}`); // 反向映射

现代替代方案:as const 对象 + 字面量联合,效果等价且零运行时开销:

const Theme = {
  Light: "light",
  Dark: "dark",
} as const;

type Theme = (typeof Theme)[keyof typeof Theme]; // "light" | "dark"

function applyTheme(theme: Theme): string {
  return theme === Theme.Dark ? "深色模式" : "浅色模式";
}

console.log(applyTheme(Theme.Light));
console.log(applyTheme("dark")); // 字面量也合法

常见坑

  • 数字枚举的反向映射藏 bug:枚举对象里值和名字互相映射,遍历时会拿到双倍条目;过滤时要按 typeof 区分。
  • const enum 在 Babel/esbuild 下报错:这些工具逐文件编译,拿不到另一个文件里 const enum 的值;项目用这类工具时禁用 const enum。
  • 给字符串枚举成员传任意字符串:Role 类型不接受普通 string("ADMIN" 字面量也不行,只能 Role.Admin)——这是设计如此,想要灵活就用 as const 方案。
  • 混用数字和字符串成员:异构枚举可读性极差,除了兼容老代码没有使用理由。

小结

enum 会产生运行时代码,字符串枚举比数字枚举实用;const enum 与部分工具链不兼容;新代码优先 as const 对象 + 字面量联合。下一章进入类——TypeScript 给 JS 类加的一整套访问控制。