5 個你應該知道的 TypeScript Utility Types
TypeScript 的型別系統是它最強大的武器之一。除了基本的型別標註,TypeScript 還內建了一系列「工具型別」(Utility Types),能讓你用更少的程式碼寫出更精確的型別定義。
今天來介紹 5 個在日常開發中最實用的 Utility Types,搭配真實的使用場景。
1. Partial — 讓所有屬性變成可選
當你需要做「部分更新」時,Partial 是你的好朋友。它把一個型別的所有屬性都變成可選的。
interface User {
name: string
email: string
age: number
}
// 更新使用者時,不需要傳所有欄位
function updateUser(id: string, updates: Partial<User>) {
// updates 可以是 { name: "新名字" } 或 { age: 25 } 或任意組合
}
updateUser("123", { name: "Alice" }) // OK
updateUser("123", { email: "new@mail.com", age: 30 }) // OK使用場景: API 的 PATCH 請求、表單的部分欄位更新、設定檔的局部覆寫。
2. Pick — 從型別中挑選特定屬性
有時候你只需要一個型別的某幾個屬性,而不是全部。Pick 讓你精確地選取需要的欄位。
interface Article {
id: string
title: string
content: string
author: string
createdAt: Date
updatedAt: Date
}
// 列表頁只需要這幾個欄位
type ArticlePreview = Pick<Article, "id" | "title" | "author" | "createdAt">
// 等同於:
// { id: string; title: string; author: string; createdAt: Date }使用場景: API 回傳的精簡版資料、元件 props 只需要部分欄位、GraphQL-style 的欄位選取。
3. Omit — Pick 的反面
和 Pick 相反,Omit 是把你不要的屬性排除掉。當你要「大部分欄位都需要,只有幾個不要」時特別好用。
interface DatabaseRecord {
id: string
createdAt: Date
updatedAt: Date
title: string
content: string
}
// 建立新紀錄時,id 和時間戳記由後端產生
type CreateInput = Omit<DatabaseRecord, "id" | "createdAt" | "updatedAt">
// 等同於:
// { title: string; content: string }使用場景: 建立資料時排除自動生成的欄位、繼承型別時移除不需要的屬性。
4. Record — 建立鍵值對映射
Record 讓你快速建立一個物件型別,指定鍵的型別和值的型別。
// 用字串聯合型別作為鍵
type Theme = "light" | "dark" | "system"
const themeLabels: Record<Theme, string> = {
light: "亮色模式",
dark: "深色模式",
system: "跟隨系統",
}
// 用在 API 回應的動態鍵值
type ApiErrors = Record<string, string[]>
const errors: ApiErrors = {
email: ["格式不正確", "已被使用"],
password: ["至少 8 個字元"],
}使用場景: 國際化翻譯對照表、表單驗證錯誤映射、設定檔的鍵值結構、狀態機的轉換表。
5. Extract 和 Exclude — 聯合型別的過濾器
這兩個是處理聯合型別(Union Types)的利器。Extract 取出符合條件的成員,Exclude 排除符合條件的成員。
type AllEvents = "click" | "scroll" | "mousemove" | "keydown" | "keyup"
// 只取滑鼠相關事件
type MouseEvents = Extract<AllEvents, "click" | "scroll" | "mousemove">
// "click" | "scroll" | "mousemove"
// 排除鍵盤事件
type NonKeyboardEvents = Exclude<AllEvents, "keydown" | "keyup">
// "click" | "scroll" | "mousemove"更進階的用法——搭配條件型別過濾物件的鍵:
interface Config {
apiUrl: string
timeout: number
debug: boolean
retries: number
}
// 只取出值為 number 的鍵
type NumberKeys = {
[K in keyof Config]: Config[K] extends number ? K : never
}[keyof Config]
// "timeout" | "retries"使用場景: 根據型別過濾事件名稱、動態產生子型別、型別層級的條件邏輯。
小結
這 5 個 Utility Types 覆蓋了日常開發中最常見的型別操作需求:
| Utility Type | 用途 | 一句話總結 |
|---|---|---|
Partial<T> |
全部變可選 | 「我只想更新一部分」 |
Pick<T, K> |
挑選屬性 | 「我只要這幾個」 |
Omit<T, K> |
排除屬性 | 「除了這幾個都要」 |
Record<K, V> |
鍵值映射 | 「用這個型別當 key,那個當 value」 |
Extract / Exclude |
過濾聯合型別 | 「從這堆型別裡挑/刪」 |
掌握這些工具型別,你的 TypeScript 程式碼會更精準、更容易維護。下次寫型別定義時,先想想有沒有現成的 Utility Type 可以用——大多數時候,答案是肯定的。
分享這篇文章