TypeScript 枚舉通過命名常量、類型安全和結構化組織,顯著提升代碼質量。使用時需根據場景選擇合適的類型(數字、字符串或常量枚舉),并權衡性能與動態訪問需求。掌握其特性和使用的場景,能在復雜項目中有效提升代碼的可維護性和健壯性。接下來我會通過案例,深入解讀Enum。
一、枚舉的核心作用
-
替代魔法值 用有意義的名稱取代硬編碼數字或字符串,減少代碼歧義。
enum StatusCode { Success = 200, NotFound = 404 } if (response.status === StatusCode.Success) { ... } // 比直接判斷200更清晰
-
類型安全 限制變量只能使用枚舉成員,編譯器會在賦值或比較時檢查類型。
enum Direction { Up, Down } let dir: Direction = Direction.Up; // 正確 dir = 3; // 錯誤:不能將數字直接賦值給枚舉類型
-
組織相關常量 將邏輯關聯的常量歸類,便于維護和擴展。
enum LogLevel { Info, Warn, Error }
二、枚舉的類型與語法
1.?數字枚舉(默認)
- 成員默認從?
0
?開始自增,也可手動賦值。 - 支持反向映射:通過值獲取名稱(僅數字枚舉)。
enum Direction {Up = 1, // 顯式賦值Down, // 自動遞增為2Left = 4,Right, // 自動遞增為5 } console.log(Direction.Down); // 輸出: 2 console.log(Direction[2]); // 輸出: "Down"(反向映射)
2.?字符串枚舉
- 成員必須顯式初始化字符串值。
- 無反方向映射,適用于需明確語義的場景。
enum LogLevel {Info = "INFO",Warn = "WARN",Error = "ERROR" } console.log(LogLevel.Info); // 輸出: "INFO"
3.?常量枚舉(const enum
)
- 編譯時被完全內聯,無運行時對象。
- 提升性能,但無法反射或動態訪問。
const enum Size { Small, Medium } let size = Size.Small; // 編譯后:let size = 0;
4.?異構枚舉(不推薦)
- 混合數字和字符串成員,易引發混亂。
enum BooleanLikeEnum {No = 0,Yes = "YES", }
5. 同名枚舉合并?
多個同名的 Enum 結構會自動合并。
enum Foo {A,
}
enum Foo {B = 1,
}
enum Foo {C = 2,
}
// 等同于
enum Foo {A,B = 1,C = 2
}
三、枚舉的高級特性
1.?計算成員與常量成員
- 常量成員:值在編譯時確定(字面量、其他常量成員引用)。
- 計算成員:值在運行時計算(需顯式初始化后續成員)。
enum FileAccess {None, // 常量成員 0Read = 1 << 1, // 計算成員 2Write = 1 << 2, // 計算成員 4ReadWrite = Read | Write, // 計算成員 6// 后續成員必須顯式初始化Execute = 8 }
2.?枚舉作為類型
- 限制變量或參數只能為枚舉成員值,這是枚舉的一個缺點。
enum UserRole { Admin, Guest } function setRole(role: UserRole) { ... } setRole(UserRole.Admin); // 正確 setRole(2); // 錯誤:類型不符
四、枚舉的優缺點對比
優點 | 缺點 |
---|---|
提升代碼可讀性 | 編譯后生成額外代碼(非 const enum) |
編譯時類型檢查 | 字符串枚舉不支持反向映射 |
支持反向映射(數字枚舉) | 異構枚舉易導致邏輯混亂 |
便于統一管理常量 | 動態訪問可能繞過類型檢查(數字枚舉) |
五、使用場景
-
優先使用字符串枚舉 提高代碼自描述性,避免數字枚舉的隱式歧義。
-
性能敏感場景用
const enum
減少生成代碼量,但需確保無需動態訪問枚舉。 -
替代方案考量
- 聯合類型:適用于簡單且無需反向映射的場景。
type LogLevel = 'INFO' | 'WARN' | 'ERROR';
- 對象常量:需手動凍結對象防止修改,無類型約束。
const LogLevel = { Info: 'INFO' } as const;
- 聯合類型:適用于簡單且無需反向映射的場景。
?引用一個例子:Enum 結構比較適合的場景是,成員的值不重要,名字更重要,從而增加代碼的可讀性和可維護性。
enum Operator {ADD,DIV,MUL,SUB
}
function compute(op:Operator,a:number,b:number
) {switch (op) {case Operator.ADD:return a + b;case Operator.DIV:return a / b;case Operator.MUL:return a * b;case Operator.SUB:return a - b;default:throw new Error('wrong operator');}
}
compute(Operator.ADD, 1, 3) // 4
?上面示例中,Enum 結構Operator
的四個成員表示四則運算“加減乘除”。代碼根本不需要用到這四個成員的值,只用成員名就夠了。
六、示例對比
枚舉 vs 聯合類型
枚舉方案:
enum Theme { Dark = 'dark', Light = 'light' }
function setTheme(theme: Theme) { ... }
setTheme(Theme.Dark);
聯合類型方案:
type Theme = 'dark' | 'light';
function setTheme(theme: Theme) { ... }
setTheme('dark');
對比:
- 枚舉集中管理常量,修改時只需調整枚舉定義。
- 聯合類型無需生成額外代碼,適合簡單場景。