有使用 TypeScript 的朋友,可能會需要在 TypeScript 中處理複雜的物件結構或字面量,尤其是與後端 API 整合時,如何讓型別既嚴謹又靈活,是個常見的挑戰。

今天想介紹的是 as const 這個功能,搭配上型別工具,可以讓我們的程式碼更安全、更具維護性唷!

定義型別時常見的問題

▼ 假設我們要定義一組固定的按鈕,例如表單操作

const buttonConfig = {
  submit: { label: "送出", disabled: false },
  cancel: { label: "取消", disabled: true },
}

我們希望這個物件的 key:submit, cancel 和值:label, disabled 都能被 TypeScript 精準推斷,而不是被寬鬆的推斷為 string{ [key: string]: any }

為什麼呢?因為常常在開發中,我們會需要基於這些物件(鍵值)做 mapping(映射) 或 rendering(渲染)。

function renderButton(type: keyof typeof buttonConfig) {
  const btn = buttonConfig[type];
  return <button disabled={btn.disabled}>{btn.label}</button>;
}

沒有特別處理的話,物件的 key 可能只會推斷為 string,而不是精確的 "submit" | "cancel",如此就會導致淺在的錯誤發生,例如傳入不存在的 key

AD

使用 as const 定義物件

▼ 如果要更精準的定義物件,我們可以在定義時加上 as const,告訴 TypeScript 這是一個「唯獨的常數物件」,這樣一來,該物件的 keyvalue 都會被精確推斷為字面量型別

const buttonConfig = {
  submit: { label: "送出", disabled: false },
  cancel: { label: "取消", disabled: true },
} as const

▼ 此時 TypeScript 推斷的型別就會變成

{
  readonly submit: { readonly label: "送出"; readonly disabled: false };
  readonly cancel: { readonly label: "取消"; readonly disabled: true };
}

而原本的 type: keyof typeof buttonConfig 會被精確推斷為 "submit" | "cancel",而不是寬鬆的 string。這在需要嚴格型別約束的場景中非常實用。

完整的語法範例

完整範例如下

const buttonConfig = {
  submit: { label: "送出", disabled: false },
  cancel: { label: "取消", disabled: true },
} as const

type ButtonType = keyof typeof buttonConfig  // "submit" | "cancel"

function renderButton(type: ButtonType) {
  const btn = buttonConfig[type]
  return <button disabled={btn.disabled}>{btn.label}</button>
}

// 正確用法

renderButton("submit"); // OK
renderButton("cancel"); // OK

// 錯誤用法,編譯時就會報錯

renderButton("reset"); // Error: Argument of type '"reset"' is not assignable to parameter of type '"submit" | "cancel"'.

實作可能會踩的雷

過度依賴 as const 而忽略動態資料

as const 只適用於靜態的、固定的資料結構。如果 buttonConfig 是從 API 動態生成的,就不能直接使用 as const,否則會失去型別的靈活性。

這時候,我們要搭配 interfacetype 來定義預期的結構,也可以在運行時做驗證 (可使用 Zod 協助,推薦閱讀:使用 ts-rest 與 Zod 定義 API 合約和進行資料驗證 )

過多的巢狀結構會影響可讀性

如果物件巢狀非常多,使用 as const 會讓型別變得非常冗長,維護起來反而麻煩。這種情況下,可以考慮拆分物件,或用 as (型別斷言) 來簡化之。

小結

as const 是一個簡單卻強大的工具,特別適合用在物件、狀態枚舉或 UI 元件的參數定義上。可以大大減少型別出錯的機率,非常值得一試唷!

希望這篇文章對你有幫助,如果有其他想深入的主題或對文章有問題,歡迎留言告訴我~。