iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
JavaScript

我推的TypeScript 操作大全系列 第 24

我推Day24 - TypeScript Enums 的神奇威力:讓程式碼更有條理的場景應用

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20241008/20124462zfm2mHET3F.jpg


Enum 超級解密!用 TypeScript 征服每一行程式碼 🌟

你是否常常在專案中遇到需要處理一堆相關數值的情境?
TypeScript 的 enum 可以幫助你將這些相關的值用一個簡單有條理的方式表示出來!
Enum 不只讓程式碼變得更易讀、維護性更高,還能減少潛在的錯誤呢!
讓我們來看看幾個實用的 enum 使用範例吧!


** 為什麼要用 Enum ?**

Enum 是 TypeScript 中一個強大的特性,能夠讓開發者定義一組命名的常量,並且可以透過名字來引用這些值,而不需要使用具體的數值或字串。
這在開發中提供了更好的可讀性和可維護性,並且避免了魔法數字(magic numbers)或魔法字串的錯誤使用。

1. 基本 Enum 結構:清晰的常量結構 🔑

enum Movement {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

Enum 的特性

  • 提升可讀性:使用 Enum 能夠為相關值提供有意義的名稱。舉例來說,當處理方向鍵輸入時,使用 Movement.Up 會比直接使用字串 "UP" 更具描述性,讓程式碼更直觀且易於理解。

  • 型別安全:Enum 提供了強大的型別檢查功能,能夠在編譯階段檢查是否使用了無效的值。例如,在 Movement Enum 中,如果我們不小心傳入了 "FORWARD" 這樣的無效值,TypeScript 就會報錯,因為 "FORWARD" 不屬於 Enum 中定義的合法值,當程式處理使用者輸入時,這樣的結構能夠避免無效值的誤用,從而減少程式錯誤。

  • 限制輸入範圍:Enum 可以限制值的範圍,確保程式僅能使用已定義好的值。這在避免使用者輸入錯誤值或開發者無意中輸入錯誤時尤其有幫助。

  • 支援字串與數字 Enum:Enum 支援數字和字串兩種格式。數字 Enum 可以自動遞增,適合需要連續數值的情境;字串 Enum 則能使值更具語義化,方便在具體應用中表達具體的狀態或類型。


2. Enum 與數值:輕鬆處理 HTTP 狀態碼 🛠

當你需要處理一些固定數字(例如 HTTP 狀態碼)時,enum 是幫助你有效整理這些狀態碼的好工具,讓程式碼更具結構性並避免錯用數字的情況。

enum StatusCode {
  OK = 200,
  BadRequest = 400,
  NotFound = 404
}

function handleResponse(code: StatusCode) {
  if (code === StatusCode.OK) {
    // 處理成功回應
  } else if (code === StatusCode.NotFound) {
    // 處理找不到資源的錯誤
  }
}

使用 enum 來替代數字值,能夠讓你的代碼更具語意化,像是 StatusCode.OK 就比直接使用數字 200 更具描述性。這樣的好處不僅在於提升可讀性,還能減少潛在的手誤,避免使用錯誤的數值。


3. Enum 與狀態管理:處理異步請求 🌀

在使用 Redux 或其他狀態管理工具時,enum 也常被用來表示異步操作的不同階段(如 loadingsuccesserror),幫助你定義清晰的狀態流程,讓異步請求更容易管理確保狀態的一致性和可預測性。

enum PayloadActionLoadingState {
  Idle = "idle",
  Loading = "loading",
  Failed = "failed",
  Success = "success" 
}

這個 enum 可以在你處理 API 請求或其他異步操作時,清楚地表示目前的狀態,讓程式碼更加清晰易懂。


4. Enum 作為區分聯合型別 (Discriminated Union) 🛸

當我們處理不同型別的物件時,enum 可以幫助我們清楚地區分不同類型,並根據物件的類型進行對應的邏輯處理。

enum ShapeType {
  Circle = "Circle",
  Rectangle = "Rectangle"
}

interface Shape {
  type: ShapeType;
}

interface Circle extends Shape {
  type: ShapeType.Circle;
  radius: number;
}

interface Rectangle extends Shape {
  type: ShapeType.Rectangle;
  width: number;
  height: number;
}

function calculateArea(shape: Shape): number {
  switch (shape.type) {
    case ShapeType.Circle:
      const circle = shape as Circle;
      return Math.PI * circle.radius * circle.radius;
    case ShapeType.Rectangle:
      const rectangle = shape as Rectangle;
      return rectangle.width * rectangle.height;
    default:
      throw new Error("無效的形狀類型");
  }
}

這樣的結構讓我們可以根據不同的形狀類型,靈活地處理不同的邏輯操作。


5. Enum 作為資料結構:建立一副撲克牌的模型 🃏

我們可以用 enum 來表示撲克牌的花色和數值,並根據花色推導出牌的顏色,這樣能讓撲克牌的資料結構更有組織性。

enum Suit {
  Hearts = "♥", // 紅心
  Diamonds = "♦", // 方塊
  Clubs = "♣", // 梅花
  Spades = "♠" // 黑桃
}

enum Rank {
  Ace = 1,
  Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten,
  Jack, Queen, King 
}

function getCardValue(rank: Rank): number {
  return rank <= Rank.Ten ? rank : 10;
}

interface Card {
  suit: Suit;
  rank: Rank;
  color: string;
}

function createCard(suit: Suit, rank: Rank): Card {
  return {
    suit,
    rank,
    color: suit === Suit.Hearts || suit === Suit.Diamonds ? 'Red' : 'Black'
  }
}

let card1 = createCard(Suit.Hearts, Rank.Ace);
console.log(`紅心 A 是 ${card1.color}`); // 輸出:紅心 A 是紅色

let card2 = createCard(Suit.Spades, Rank.Queen);
console.log(`黑桃 Q 是 ${card2.color}`); // 輸出:黑桃 Q 是黑色

這個例子展示了如何使用 enum 來結合撲克牌的花色和數值,讓程式碼更具結構性和易讀性。


拓展 Enum 與泛型的結合應用

Enum 是 TypeScript 中一個強大而靈活的功能,通常用來定義一組固定的值。
然而,當結合泛型 (Generics) 時,Enum 的使用將更加靈活,讓你能夠根據不同的情況精確地操控 Enum 的值。

泛型與 Enum 的進階應用

當你需要從 Enum 中動態取得對應的值時,可以使用泛型來實現更靈活的邏輯處理。舉個例子,我們定義了一個 StatusCode Enum,它包含了幾個常見的 HTTP 狀態碼:

enum StatusCode {
  OK = 200,
  BadRequest = 400,
  NotFound = 404
}

function getEnumValue<T extends keyof typeof StatusCode>(key: T): StatusCode[T] {
  return StatusCode[key];
}

console.log(getEnumValue("OK")); // 200
console.log(getEnumValue("NotFound")); // 404

在這個範例中,T extends keyof typeof StatusCode 意味著我們的泛型 T 必須是 StatusCode 中的某個鍵值。
這樣可以確保在呼叫 getEnumValue 時,傳入的鍵一定是 StatusCode 的成員之一,並且返回對應的 Enum 值。這樣的結合使得程式碼更具彈性與型別安全性,特別是在需要動態操作 Enum 值時,泛型能夠提供更靈活的處理方式。


const enumenum 的差異

在 TypeScript 中,你可以使用 const enum 來進一步優化編譯後的程式碼。const enum 與普通的 enum 最大的區別在於,它在編譯後不會產生冗餘的 JavaScript 代碼。相反,TypeScript 會直接將 const enum 的成員值替換為對應的數值或字串,從而減少編譯後的代碼大小,特別是在需要高效處理的專案中,const enum 顯得尤為重要。

範例:const enum 的優化

const enum Direction {
  Up,
  Down,
  Left,
  Right
}

const move = Direction.Up; // 編譯後直接成為數值

在這個例子中,Direction.Up 會在編譯後被替換為數值 0,而不會像普通 enum 那樣生成冗長的代碼。這種優化對於減少大型專案中的代碼體積非常有幫助。

然而,需要注意的是,const enum 在使用 isolatedModules 或某些編譯器設置時,可能會有一些限制。由於它不會生成實際的 JavaScript 代碼,因此在某些情況下可能無法正常運行。如果你的專案需要這種特性,使用普通 enum 可能會更加安全。


與其他語言中的 Enum 比較

Enum 的概念並不是 TypeScript 的獨創,它在許多傳統語言中(例如 C、C++、Java 和 C#)早已存在並被廣泛使用。
TypeScript 將 Enum 帶入了 JavaScript 的世界,並在原本的基礎上進行了一些改良,讓 JavaScript 開發者也能體驗到強大的 Enum 功能。

在 Java 和 C# 中,Enum 通常被用來定義一組固定的常數值,例如一周的天數或方向。在這些語言中,Enum 也具備類似的功能,不過 TypeScript 的 Enum 更加靈活,支持數值和字串的定義,並且能夠與泛型結合使用。

對於來自這些語言背景的開發者,TypeScript 的 Enum 會讓他們感到熟悉,但同時也提供了更多的靈活性。


Enum 的限制與替代方案

雖然 Enum 非常實用,但它並不是解決所有問題的靈丹妙藥。
Enum 也有一些限制,特別是在大型應用中或性能優化的情況下可能會遇到一些坑。這些限制包括:

  • 編譯後代碼過於冗長:普通的 Enum 在編譯後會產生較多的代碼,這會增加最終 JavaScript 檔案的大小。如果頻繁使用 Enum,這個問題可能會加劇。

  • 靈活性不足:Enum 是靜態的,當需要動態定義鍵或值時,它可能無法滿足需求。在這種情況下,可以考慮使用更靈活的 union types 或物件來模擬 Enum 的功能。

替代方案:使用聯合型別代替 Enum

聯合型別 (union types) 是 TypeScript 中另一個強大的功能,它能夠提供比 Enum 更加輕量且靈活的解決方案。
例如,我們可以用聯合型別來模擬方向枚舉:

type Direction = "Up" | "Down" | "Left" | "Right";
const move: Direction = "Up"; // 使用聯合型別代替 enum

聯合型別不會在編譯後生成額外的 JavaScript 代碼,因此在某些場景下,它可以成為 Enum 的一個替代選擇,特別是當需要高度靈活的動態處理時。


小結:掌握 Enum 的靈活應用

  1. enum 提升可讀性與型別安全

    • enum 讓代碼更具語意化,例如 Movement.Up 明確地代表方向,而不是使用字串 "UP" 或數值。
    • 提供型別檢查,避免無效值傳入。
  2. enum 支援字串與數字類型

    • enum 支援數字自動遞增,也支持字串值。使用字串時,值的語義性更強,適合處理狀態或類型。
  3. 泛型與 enum 結合

    • 結合泛型可以讓 enum 更靈活,能夠動態取得對應的 enum 值,增加型別安全性,適合在需要靈活操作時使用。
  4. const enum 的優化

    • 使用 const enum 可以減少編譯後的代碼大小,提高性能。在大型專案中,這是優化代碼的有效方法。
    • 然而,const enum 可能在某些編譯設置中有限制,需根據專案需求使用。
  5. 聯合型別作為替代方案

    • 在需要靈活、動態處理時,聯合型別(union types)可以替代 enum,並且不會在編譯後生成多餘的代碼,適合簡單場景。
  6. 與其他語言中的 enum 比較

    • TypeScript 的 enum 借鑒了其他語言中的設計(例如 Java、C#),但加入了字串支持和與泛型結合的靈活性,讓其更適合 Web 開發。

TypeScript 的 enum 真的是一個強大的工具!
它能夠提升程式碼的可讀性和維護性,讓你的專案更加穩固和有條理。
下次當你需要處理相關值的集合時,不妨考慮使用 enum 來簡化程式碼,讓你的程式碼更加優雅吧!💪


上一篇
我推Day23 - 超強 TypeScript 陣列方法解析:讓你事半功倍的 6 大終極技巧!
下一篇
我推Day25 - 讓 TypeScript 炸裂你的腦袋!用映射型別打造超型別安全的解析器技巧
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言