iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0

1) 引言:為什麼需要 Template Literal Types?

在 JavaScript 裡,我們可以用模板字串:

ts
CopyEdit
const name = "Alice";
const message = `Hello, ${name}!`;

TypeScript 從 4.1 開始,讓型別系統也能玩這種「字串拼接」,

而且還能搭配 Union條件型別 來自動生成型別。

這意味著:

  • 你可以自動生成 API 路徑型別
  • 你可以生成事件名稱型別(例如 "onClick""onChange"
  • 甚至可以做字串轉換(大寫、小寫、首字母大寫)

2) 基本語法

ts
CopyEdit
type EventName<T extends string> = `on${Capitalize<T>}`;

type ClickEvent = EventName<"click">; // "onClick"

這裡:

  • 反引號 ... 是模板字面型別語法
  • ${} 裡面可以放 型別參數 或其他型別運算
  • Capitalize<T> 是 TS 內建的字串轉換工具

3) 內建字串操作工具型別

  • Uppercase<S>:轉成全大寫
  • Lowercase<S>:轉成全小寫
  • Capitalize<S>:首字母大寫
  • Uncapitalize<S>:首字母小寫

範例:

ts
CopyEdit
type A = Uppercase<"hello">; // "HELLO"
type B = Lowercase<"Hello">; // "hello"
type C = Capitalize<"hello">; // "Hello"
type D = Uncapitalize<"Hello">; // "hello"


4) 搭配 Union 產生多個型別

ts
CopyEdit
type Events = "click" | "change";
type EventHandlers = `on${Capitalize<Events>}`;
// "onClick" | "onChange"

這招在定義事件名稱、API 路徑、CSS class 名稱等非常好用。


5) 實戰應用 1:API 路徑生成

ts
CopyEdit
type Endpoints = "users" | "posts" | "comments";
type ApiPaths = `/api/${Endpoints}`;
// "/api/users" | "/api/posts" | "/api/comments"

這樣改 API 路徑名稱只要改一個地方,型別會自動更新。


6) 實戰應用 2:事件名稱型別化

ts
CopyEdit
type BaseEvents = "click" | "hover" | "focus";
type DOMEvents = `on${Capitalize<BaseEvents>}`;

function addEventListener<E extends DOMEvents>(event: E) {
  console.log(`Listening to ${event}`);
}

addEventListener("onClick"); // OK
addEventListener("onHover"); // OK
addEventListener("onclick"); // ❌ 型別錯誤


7) 實戰應用 3:狀態機 Key 生成

ts
CopyEdit
type States = "loading" | "success" | "error";
type StateLabels = `${Uppercase<States>}_STATE`;
// "LOADING_STATE" | "SUCCESS_STATE" | "ERROR_STATE"


8) 實戰應用 4:駝峰與底線轉換(進階)

ts
CopyEdit
type SnakeToCamel<S extends string> =
  S extends `${infer First}_${infer Rest}`
    ? `${First}${Capitalize<SnakeToCamel<Rest>>}`
    : S;

type A = SnakeToCamel<"user_name">; // "userName"

這個技巧可以搭配 Day 25 的映射型別,把 API 回應自動轉成駝峰命名。


9) 常見錯誤與陷阱

錯誤 1:把值當型別

ts
CopyEdit
const path = "/api/users";
type Wrong = `/api/${path}`; // ❌ path 是值,不是型別

→ 必須改成字面型別:

ts
CopyEdit
type Path = "/api/users";
type Correct = `/api/${Path}`;

錯誤 2:忘記 extends string 限制

ts
CopyEdit
type Test<T> = `prefix-${T}`; // ❌ 可能不是 string

→ 應該:

ts
CopyEdit
type Test<T extends string> = `prefix-${T}`;


10) 心法

  1. 模板字面型別最強的地方是搭配 Union
    • 一次生成多種可能字串型別
  2. 和映射型別組合威力更大
    • 可以批量改鍵名、批量生成路徑
  3. 可以配合條件型別做字串轉換
    • 自動駝峰化、底線化、加前後綴

上一篇
Day 25|映射型別:批量改造型別結構
下一篇
Day 27|型別驅動的表單生成器實戰
系列文
我與型別的 30 天約定:TypeScript 入坑實錄27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言