Skip to content

Type Guard 與 Enum 的應用

Type Guard

文字上翻譯的 Type Guard 就是類型守衛。我們經常需要根據後端的 API 響應或是程式碼邏輯操作來建立複雜的類型。有時候 VS Code 會報錯,提示我們需要排除一些不確定的類型定義。我們可以透過官方定義的 Utility Types 來做一些操作,但更多時候我們需要自行設計這些複雜的類型定義,以將型別限縮在我們希望的範圍中,這時類型守衛就派上了用場。

INFO

Type Guard 是一種 Run time 檢查,用來細化變量的類型範圍。

基本用法

Type Guard 是一種特殊的函數,它根據某些條件來判斷變量是否屬於特定類型。

typescript
function isNumber(value: any): value is number {
  return typeof value === "number";
}

const someValue: number = 42;

if (isNumber(someValue)) {
  console.log(`${someValue} is a number`);
} else {
  console.log(`${someValue} is not a number`);
}

Enum

枚舉是一種會被編譯的類型,用於定義一組命名的常量。它可以幫助我們更清晰地表達特定的數值集合,提高程式碼的語義和可讀性。 Enum 可以用數字或字符串作為枚舉值,且默認情況下,Enum 的值會從數字 0 開始自動遞增。

typescript
enum Color {
  Red = 0,
  Green = 1,
  Blue = 2,
}

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

結合案例

這時我遇到了一個案例希望能在實作邏輯中添加枚舉的型別守衛,透過這種方式,我們能夠用通順地語義,描述我們的邏輯。

example

進階使用範例

假設我們需要處理來自後端的複雜 API 響應數據,這些數據可能包含多種類型的信息。我們可以結合 Enum 和 Type Guard 來進行類型檢查,確保數據的正確性和一致性。

typescript
enum ApiResponseStatus {
  Success = "SUCCESS",
  Error = "ERROR",
  Loading = "LOADING",
}

interface ApiResponseBase {
  status: ApiResponseStatus;
}

interface ApiResponseSuccess<T> extends ApiResponseBase {
  status: ApiResponseStatus.Success;
  data: T;
}

interface ApiResponseError extends ApiResponseBase {
  status: ApiResponseStatus.Error;
  message: string;
}

interface ApiResponseLoading extends ApiResponseBase {
  status: ApiResponseStatus.Loading;
}

type ApiResponse<T> = ApiResponseSuccess<T> | ApiResponseError | ApiResponseLoading;

function isApiResponseSuccess<T>(
  response: ApiResponse<T>
): response is ApiResponseSuccess<T> {
  return response.status === ApiResponseStatus.Success;
}

function isApiResponseError<T>(response: ApiResponse<T>): response is ApiResponseError {
  return response.status === ApiResponseStatus.Error;
}

function isApiResponseLoading<T>(
  response: ApiResponse<T>
): response is ApiResponseLoading {
  return response.status === ApiResponseStatus.Loading;
}

async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
  const response = await fetch(url);
  const data = await response.json();

  if (response.ok) {
    return {
      status: ApiResponseStatus.Success,
      data: data as T,
    };
  } else {
    return {
      status: ApiResponseStatus.Error,
      message: "Failed to fetch data",
    };
  }
}

async function handleApiResponse<T>(url: string) {
  const response = await fetchData<T>(url);

  if (isApiResponseSuccess(response)) {
    console.log("Data:", response.data);
  } else if (isApiResponseError(response)) {
    console.error("Error:", response.message);
  } else if (isApiResponseLoading(response)) {
    console.log("Loading...");
  } else {
    console.error("Unknown response status");
  }
}

handleApiResponse<{ id: number; name: string }>("https://api.example.com/getData");

總結

我們深入討論了 TypeScript 中的類型守衛(Type Guard)和枚舉(Enum),並嘗試結合這兩種強大的工具來提高代碼的安全性和可維護性。 Type Guard 允許我們在運行時進行精確的類型檢查,而枚舉提供了一種清晰且有語義的方式來定義一組命名常量。

通過實際範例,我們展示了如何在處理複雜的 API 響應數據時使用這些技術。 嘗試使用看看吧~

參考資料

Released under the MIT License.