TypeScript 列舉 (Enum)
Enum (列舉) 是一個從其他語言(如 C# 或 Java)借鏡過來的概念,用來定義「一組命名的常數」。
不過在 TypeScript 中,Enum 的地位比較特殊,因為它不只是型別,它還會產生真實的 JavaScript 程式碼。這讓許多現代開發者對它又愛又恨。
數字列舉 (Numeric Enum)
這是最常見的用法。
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
// 使用
let go: Direction = Direction.Up;
你也可以手動指定值:
enum StatusCode {
OK = 200,
NotFound = 404,
Error = 500,
}
字串列舉 (String Enum)
如果要讓值更有意義(例如方便 debug),可以用字串列舉。
enum Color {
Red = 'RED',
Green = 'GREEN',
Blue = 'BLUE',
}
⚠️ 現代 TypeScript 的爭議:Enum vs Union Types
這是這篇文章最重要的部分。 現在很多資深開發者(包含 TypeScript 官方的一些範例)更傾向使用 Union Types (聯合型別) 而非 Enum。
Enum 的問題
- 編譯產物:Enum 會被編譯成一個 JavaScript物件 (IIFE),會增加一點點 bundle size。
- 行為怪異:數字 Enum 可以被反向查表 (Reverse Mapping),但字串 Enum 不行。
現代替代方案:Union Types
// ✅ 推薦做法:使用字面量聯合型別
type Direction = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT';
function move(dir: Direction) {
// ...
}
move('UP'); // 直觀、簡單,沒有額外的 JS 產物
現代替代方案:const as const
如果你需要像 Enum 一樣用「物件」來管理常數,可以這樣寫:
// ✅ 推薦做法:Object as const
const Color = {
Red: 'RED',
Green: 'GREEN',
Blue: 'BLUE',
} as const;
// 產生型別: "RED" | "GREEN" | "BLUE"
type Color = (typeof Color)[keyof typeof Color];
// 使用方式跟 Enum 一模一樣
console.log(Color.Red); // "RED"
總結:我該用哪個?
| 方案 | 優點 | 缺點 | 建議場景 |
|---|---|---|---|
| Enum | 語法簡單,有名字 | 會產生額外 JS 程式碼 | 需要「數字」對應「名字」時 (如 Error Code) |
| Union Types | 最輕量,完全不佔空間 | 無法像物件一樣迭代 | (⭐️ 推薦) 大多數的字串選項 |
| const object | 輕量且保有物件特性 | 語法稍微囉嗦一點 | 需要物件形式管理常數時 |
從簡原則:如果你只是需要一組字串選項(如 'primary' | 'secondary'),直接用 Union Types 就好,最乾淨也最快。