枚举与字面量类型
2026/7/9大约 5 分钟
枚举与字面量类型
概述
Go 使用 iota 实现枚举常量,类型安全但功能有限。TypeScript 提供了两种枚举机制:传统的 enum(数字/字符串枚举)和更推荐的字面量联合类型 + as const。对于 Go 开发者来说,理解为何 TS 社区逐渐倾向于用字面量类型替代 enum,是掌握 TS 类型风格的重要一步。
Go 开发者已知
// Go 枚举 —— iota
type Status int
const (
StatusActive Status = iota // 0
StatusInactive // 1
StatusPending // 2
StatusDeleted // 3
)
// 自定义起始值
const (
StatusA Status = iota + 10 // 10
StatusB // 11
StatusC // 12
)
// 跳过某些值
const (
StatusX Status = iota // 0
_ // 1(跳过)
StatusY // 2
)
// 字符串枚举
type Color string
const (
ColorRed Color = "red"
ColorGreen Color = "green"
ColorBlue Color = "blue"
)Go 枚举特点:
- 基于
iota的整数自增 - 类型安全(不同枚举类型不能混用)
- 表达能力有限,无法包含方法
- 没有反射级的枚举遍历能力
TypeScript 怎么做
数字枚举
enum Status {
Active, // 0
Inactive, // 1
Pending, // 2
Deleted, // 3
}
// 自定义初始值
enum StatusExplicit {
Active = 1,
Inactive = 2,
Pending = 4,
Deleted = 8, // 位标志
}
// 使用
const s: Status = Status.Active
console.log(s) // 0
console.log(Status[0]) // "Active"(反向映射)字符串枚举
enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue',
}
// 字符串枚举没有反向映射
console.log(Color.Red) // "red"
// console.log(Color['red']) // Error
// 混合枚举(不推荐)
enum Mixed {
Yes = 1,
No = 'no',
}const enum(常量枚举)
const enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
// const enum 在编译时被内联,没有运行时产物
const dir = Direction.Up // 编译后: const dir = 'UP'const enum 的限制
const enum 不能在使用 isolatedModules: true 的构建工具(如 Vite、Babel)中使用。如需跨文件常量枚举,使用普通 enum 或 as const 替代。
字面量联合类型(推荐)
// 用字面量联合类型替代 enum
type Status = 'active' | 'inactive' | 'pending'
function handleStatus(s: Status): void {
switch (s) {
case 'active':
break
case 'inactive':
break
case 'pending':
break
default:
const _exhaustive: never = s
}
}as const
// as const 将对象变为深度只读常量
const Colors = {
Red: '#FF0000',
Green: '#00FF00',
Blue: '#0000FF',
} as const
// Colors.Red 的类型是 '#FF0000'(字面量类型),而非 string
// 获取值的联合类型
type ColorValue = (typeof Colors)[keyof typeof Colors]
// '#FF0000' | '#00FF00' | '#0000FF'
// as const 与数组
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE'] as const
type HttpMethod = (typeof HTTP_METHODS)[number]
// 'GET' | 'POST' | 'PUT' | 'DELETE'差异分析
| 维度 | Go | TypeScript |
|---|---|---|
| 枚举机制 | iota 自增 | enum / 字面量联合 / as const |
| 类型安全 | 强类型独立枚举 | 结构兼容,枚举间可赋值 |
| 运行时开销 | 无 | enum 有运行时对象;const enum/字面量无 |
| 反向映射 | 不支持 | 数字 enum 支持 |
| 位标志 | 手动 iota 位移 | 数字枚举支持 |
| 字符串枚举 | const string 模拟 | 原生支持 |
| 推荐实践 | iota | 优先 as const + 联合类型 |
为何 TS 社区倾向用字面量类型替代 enum?
- Tree-shaking 友好:
enum编译为 IIFE,无法被树摇 - 类型更精确:字面量联合类型在类型检查时更严格
- 与数据交互自然:后端 API 返回的字符串天然是字面量类型
- 与外部接口兼容:JSON 序列化/反序列化不需要转换逻辑
// enum —— 运行时存在,无法 tree-shake
enum Status { Active = 'active' }
// 字面量联合 —— 纯编译时,零运行时开销
type Status = 'active' | 'inactive'Bad Practice
// Bad: 数字枚举的隐式赋值导致安全隐患
enum Permission {
Read, // 0
Write, // 1
Execute, // 2
// 如果以后在 Read 前插入一个新值,所有值都会变!
}
// Bad: 混用不同类型枚举值
enum Mixed {
Yes = 1,
No = 'no', // 混合数字和字符串
}
// Bad: 使用 enum 表达单纯的字符串常量组
enum Colors {
Red = '#FF0000',
Green = '#00FF00',
}
// 直接用 as const + 联合类型更好
// Bad: 依赖数字枚举的隐式值
enum Fruit {
Apple, // 假设是 0
Banana, // 1
Orange, // 2
}
// 如果有人添加了条目,所有索引都会受影响Best Practice
// Good: 优先 as const + 联合类型
const Colors = {
Red: '#FF0000',
Green: '#00FF00',
Blue: '#0000FF',
} as const
type Colors = keyof typeof Colors // 'Red' | 'Green' | 'Blue'
type ColorValues = (typeof Colors)[keyof typeof Colors]
// '#FF0000' | '#00FF00' | '#0000FF'
// Good: 当需要运行时枚举行为时使用普通 enum
enum HttpStatus {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500,
}
// 利用数字枚举的反向映射调试
console.log(HttpStatus[200]) // "OK"
// Good: 字面量联合类型 + 穷举检查
type Direction = 'north' | 'south' | 'east' | 'west'
function move(direction: Direction): void {
switch (direction) {
case 'north': break
case 'south': break
case 'east': break
case 'west': break
default: {
const _exhaustive: never = direction
}
}
}
// Good: 位标志使用数字枚举
enum FileAccess {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Execute = 1 << 2,
ReadWrite = Read | Write,
All = Read | Write | Execute,
}如何选择枚举方案?
| 场景 | 推荐方案 |
|---|---|
| 简单字符串常量组 | as const + 联合类型 |
| 需要穷举检查的 switch | 字面量联合类型 |
| 需要运行时遍历 | 普通 enum |
| 位标志操作 | 数字 enum |
| 外部 API 数据(JSON) | 字面量联合类型 |
| 需要反向映射(调试) | 数字 enum |
| 构建工具不支持 const enum | 字面量联合类型或普通 enum |
code-tabs 对比
总结
| Go 习惯 | TypeScript 对应 |
|---|---|
iota 数字枚举 | enum 数字枚举 或 as const |
string 常量组 | 字面量联合类型 |
| 位标志 | 数字枚举位运算 |
| 类型安全枚举 | 字面量类型 + 穷举检查 |
| 反射遍历 | Object.values(enum) |
核心建议:在 TypeScript 中,优先使用 as const + 字面量联合类型,仅在需要运行时特性(反向映射、位运算、迭代)时才使用 enum。
下一章将介绍 类型守卫与类型断言。