TypeScript 狀態映射實戰:從枚舉到多語言的最佳實踐
在前后端分離的開發模式中,后端接口常通過數字或字符串形式的枚舉值(如 0、1、"draft")表示業務狀態、類型等信息。而前端不僅需要將這些值轉換為用戶友好的文本(如中文“草稿”、英文“Draft”),還需考慮多語言切換、狀態合法性校驗等問題。本文將深入探討 ?5 種常見的狀態映射方案,從最基礎的枚舉反向映射到面向企業的 Class 封裝,分析其適用場景、類型安全性和擴展能力。
一. ?直接根據值渲染
<template>
<div class="content">
<!-- 直接根據 valueFromBackend 顯示狀態 -->
<span v-if="valueFromBackend === StatusMap.DRAFT">未確認</span>
<span v-else-if="valueFromBackend === StatusMap.PUBLISHED">已發布</span>
<span v-else-if="valueFromBackend === StatusMap.DELETED">已刪除</span>
<span v-else>未知狀態</span>
</div>
</template>
<script setup lang="ts">
//用原生js定義
const StatusMap = {
DRAFT: 0,
PUBLISHED: 1,
DELETED: 2
};
//使用ts定義
export enum Status {
DRAFT = 0,
PUBLISHED = 1,
DELETED= 2
}
const valueFromBackend = 0; // 假設后端返回 0
</script>
優點
- ?簡單快捷:無需額外定義映射對象,直接利用 TypeScript 枚舉的反向映射特性。
- ?代碼量少:適合快速原型開發或簡單狀態判斷。
?缺點
- ?強耦合枚舉鍵名:模板中硬編碼枚舉鍵名(如
'Unconfirmed'),鍵名修改后需全局替換。 - ?無法處理非法值:若
row.type為非法值(如3),Status[3]返回undefined,但無錯誤提示。 - ?不支持多語言:文本直接寫在模板中,難以擴展國際化。
- ?類型不安全:反向映射的返回值類型為
string | undefined,需手動處理。
?適用場景
- 臨時調試或小型項目,無需長期維護。
- 狀態值穩定且無需國際化。
二. ?數組遍歷寫法
<template>
<ul>
<li v-for="status in statusList" :key="status.value">
<template v-if="valueFromBackend === status.value">
{{ status.label }}
</template>
</li>
</ul>
</template>
<script setup>
const statusList = [
{ value: 0, label: '未確認' },
{ value: 1, label: '已確認' }
];
const valueFromBackend = 0;
</script>
優點
- ?結構清晰:狀態值與文本集中管理,便于擴展新狀態。
- ?動態渲染:適合需要遍歷所有狀態并高亮當前值的場景(如狀態篩選菜單)。
?缺點
- ?性能開銷:每次渲染需遍歷整個數組,狀態較多時可能影響性能。
- ?邏輯重復:狀態判斷邏輯分散在模板中,可能產生冗余代碼。
- ?類型松散:未使用 TypeScript 約束,可能因拼寫錯誤導致運行時問題。
?適用場景
- 需要動態生成狀態列表的界面(如篩選器、選項卡)。
- 狀態數量較少且變化頻繁。
三. ?枚舉 + 映射對象寫法
<template>
<div class="content">
<span>{{ StatusChinese[valueFromBackend as Status] }}</span>
</div>
</template>
<script setup lang="ts">
enum Status {
Unconfirmed = 0,
Confirmed = 1,
}
const StatusChinese = {
[Status.Unconfirmed]: '未確認',
[Status.Confirmed]: '已確認',
} as const;
const StatusEnglish = {
[Status.Unconfirmed]: 'unconfirmed',
[Status.Confirmed]: 'Confirmed',
} as const;
// 獲取中文
console.log(StatusChinese[backendValue]); // 輸出 "草稿"
// 獲取英文
console.log(StatusEnglish[backendValue]); // 輸出 "Draft"
const valueFromBackend = 0; // 假設后端返回 0
</script>
優點
- ?類型安全:通過
as Status和as const確保類型正確,編譯時檢查非法值。 - ?解耦鍵名與文本:修改枚舉鍵名不影響顯示邏輯,只需更新映射對象。
- ?擴展性強:輕松支持多語言(替換映射對象即可)。
- ?集中維護:狀態文本統一管理,避免硬編碼。
?缺點
- ?代碼量略多:需定義枚舉和映射對象,小型項目可能顯得冗余。
- ?學習成本:需熟悉 TypeScript 高級特性(如
as const和類型守衛)。
?適用場景
- 中大型項目或長期維護的代碼庫。
- 需要國際化、主題切換等擴展功能。
四.Class 封裝
class OrderStatus { // 定義枚舉值 static readonly Draft = 0; static readonly Published = 1; static readonly Deleted = 2; // 私有映射表 private static zhMap = { [OrderStatus.Draft]: "草稿", [OrderStatus.Published]: "已發布", [OrderStatus.Deleted]: "已刪除", } as const; // 獲取中文 static getChinese(value: number): string { return this.zhMap[value as keyof typeof this.zhMap] || "未知狀態"; } // 校驗合法性 static isValid(value: number): boolean { return Object.values(OrderStatus).includes(value); } } // 使用示例 console.log(OrderStatus.getChinese(0)); // "草稿"
優點
- ?邏輯高度集中:狀態值、映射關系、校驗方法全部封裝在類中。
- ?強封裝性:私有映射表 (
zhMap) 避免外部誤修改。 - ?易于擴展:可添加更多方法(如多語言、日志記錄)。
- ?類型安全:靜態方法配合
keyof實現安全訪問。
?缺點
- ?代碼冗余:簡單場景下顯得過于繁瑣。
- ?過度設計:小型項目可能不需要完整的面向對象結構。
- ?初始化成本:需實例化或靜態調用,略失靈活性。
?適用場景
- 復雜狀態邏輯(如狀態機、流程審批)。
- 需要集中管理校驗、轉換、日志等附加功能。
- 團隊熟悉面向對象設計模式。
五.聯合類型 + 對象映射
// 定義聯合類型 type StatusValue = 0 | 1 | 2; // 定義映射對象 const StatusMap = { 0: { en: "Draft", zh: "草稿" }, 1: { en: "Published", zh: "已發布" }, 2: { en: "Deleted", zh: "已刪除" }, } as const; // 類型安全訪問函數 const getStatusText = (value: StatusValue) => { return StatusMap[value] || { en: "Unknown", zh: "未知狀態" }; }; // 使用示例 console.log(getStatusText(0).zh); // "草稿"
優點
- ?極簡輕量:無需定義枚舉或類,直接通過對象和類型約束。
- ?靈活直觀:對象字面量清晰表達鍵值關系。
- ?類型精確:聯合類型
StatusValue嚴格限制取值范圍。 - ?無額外抽象:適合快速開發或簡單狀態管理。
?缺點
- ?維護成本高:新增狀態需修改聯合類型和映射對象。
- ?無法動態擴展:聯合類型需靜態定義所有可能值。
- ?復用性差:邏輯分散,不適合跨組件復用。
?適用場景
- 狀態數量固定且極少變化的場景。
- 輕量級工具函數或臨時模塊。
- 開發者偏好函數式編程風格。
六.總結
1. ?簡單場景
- ?推薦方案:初級寫法(反向映射)或數組遍歷寫法
- ?理由:快速實現,代碼量少,適合臨時需求或狀態極少變化的場景。
2. ?企業級項目
- ?推薦方案:枚舉 + 映射對象 或 Class 封裝
- ?理由:類型安全、解耦鍵名與文本,長期維護成本低,適合中大型項目。
3. ?動態列表需求
- ?推薦方案:數組遍歷寫法
- ?理由:直接遍歷狀態列表,靈活渲染 UI(如篩選菜單、選項卡)。
4. ?國際化/多主題
- ?推薦方案:枚舉 + 映射對象 + 語言包(如
i18n) - ?理由:集中管理多語言文本,輕松擴展新語言,與國際化庫無縫集成。

浙公網安備 33010602011771號