iT邦幫忙

2024 iThome 鐵人賽

DAY 28
1
JavaScript

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

我推Day28 - 用這 5 大進階技巧,讓 TypeScript 成為你的秘密武器

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20241012/20124462WFbX8mwdTj.jpg

TypeScript 進階技巧:字串字面型別插值與其他技術深入解析

TypeScript 是一個強大的工具,它不僅提供靜態型別檢查,還提供了許多高階功能,讓開發者能編寫更靈活、健壯的程式碼。在這篇文章中,我們將探索 5 個實用的 TypeScript 技巧,深入解釋其運作方式,幫助你更好地掌握這些進階特性。


1. 字串字面型別插值 🔡

TypeScript 中的字串字面型別不僅能表達固定的字串值,還能夠基於其他型別進行動態插值,類似於 JavaScript 中的字串模板語法。這樣的特性非常適合創建符合某種規則的字串型別,幫助你在程式設計中保持一致性。

技術概念:

字串字面型別插值允許你將字串與其他型別結合,創建一個動態的字串組合。例如,我們可以將 "user" 與 "Changed" 結合,生成 userChanged

例子:

type EventName<T extends string> = `${T}Changed`;
type UserEvent = EventName<"user">; // type UserEvent = "userChanged"

應用場景:

這個技術在處理事件系統時尤其有用,你可以用它來自動生成一致的事件名稱,避免手動拼接字串造成的錯誤。也可以使用在自動生成 getter 方法的名稱上。

type Getter<T extends string> = `get${Capitalize<T>}`;
type UserGetter = Getter<"username">; // type UserGetter = "getUsername"

這種字串操作不僅提升了程式碼的可讀性,還減少了代碼重複,特別是在大型專案中,能大幅減少手動操作字串的出錯率。


2. 使用交集創建品牌型別 🔗

品牌型別(Branded Types)是 TypeScript 中的一個進階模式,它允許你在結構型別系統中引入名義型別,從而讓同樣的原始型別(例如 string)被區分為不同的具名型別,這能防止不同概念的型別之間發生錯誤操作。

技術概念:

品牌型別使用交集運算符 &readonly brand: unique symbol 來創建獨一無二的型別,這樣即使兩個型別底層都是 string,也不會在 TypeScript 中被混淆。

例子:

type UserId = string & { readonly brand: unique symbol };
type PostId = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
    return id as UserId;
}

function createPostId(id: string): PostId {
    return id as PostId;
}

const userId = createUserId("user123");
const postId = createPostId("post456");

// 錯誤:不能將 UserId 分配給 PostId
// const error = userId = postId;

應用場景:

這在需要明確區分不同類型的標識符(如 UserIdPostId)時非常有用,確保它們不會被混淆使用,即使底層都是字串。在涉及 ID、代碼或任何唯一標識符的應用中,品牌型別可以顯著提高程式的安全性。


3. 使用 infer 提取型別 🧐

TypeScript 中的 infer 關鍵字是條件型別的一部分,它允許你從複雜的型別結構中提取型別資訊,並將其應用於後續邏輯。這在需要對函數回傳值、Promise 結果等進行型別推斷時非常有用。

技術概念:

在條件型別中使用 infer 可以從給定型別中推斷出內部結構,然後將其提取並使用。這種方式非常適合解包 Promise 型別或推斷函數的回傳值型別。

例子:提取 Promise 的解包型別

type UnpackPromise<T> = T extends Promise<infer U> ? U : T;

type ResolvedType = UnpackPromise<Promise<string>>; // type ResolvedType = string
type NonPromiseType = UnpackPromise<number>; // type NonPromiseType = number

例子:提取函數的回傳型別

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function fetchUser() { return { id: 1, name: "John" }; }
type User = ReturnType<typeof fetchUser>; // type User = { id: number; name: string; }

應用場景:

這種模式讓我們可以對於未知的函數或 Promise 型別進行提取和操作,尤其在動態程式設計中提供了極大的靈活性。例如,你可以用它來編寫泛型函數,根據輸入動態推斷型別,從而減少手動定義型別的麻煩。


4. 模板字面型別

模板字面型別允許你在型別層級上進行字串操作,類似於 JavaScript 中的模板字串,這種型別結合了字串插值和條件型別,能在型別定義上強制字串模式,這在處理字串嚴格規範(如 API 路徑、樣式名稱)時非常實用。

技術概念:

模板字面型別透過 type 來定義可以套用動態插值的字串,讓 TypeScript 進行靜態型別檢查。例如,你可以限制只接受特定模式的字串,防止不正確的字串格式被傳入。

例子:

type ColorVariant = "light" | "dark";
type Color = "red" | "green" | "blue";
type Theme = `${ColorVariant}-${Color}`;

function setTheme(theme: Theme) {
    // 處理主題設定
}

setTheme("light-red"); // OK
// setTheme("medium-purple"); // 錯誤:參數型別不符合 'Theme'

應用場景:

模板字面型別非常適合 CSS-in-JS 庫、路由定義、API URL 等應用中,這些地方通常對字串有特定的命名規則,使用模板字面型別能確保符合這些規則。


5. 遞迴型別別名 🔄

遞迴型別允許型別自我引用,這對於表示樹狀結構或複雜的嵌套結構非常有用。在處理 API 回應的嵌套 JSON 或者文件結構時,遞迴型別能夠有效地描述層級結構。

技術概念:

遞迴型別的概念在於型別別名可以自我引用,用來表示無限深度的嵌套資料。這特別適合描述 JSON 等複雜結構。

例子:

type JSONValue = 
    | string 
    | number 
    | boolean 
    | null 
    | JSONValue[] 
    | { [key: string]: JSONValue };

const data: JSONValue = {
    name: "John Doe",
    age: 30,
    isStudent: false,
    hobbies: ["reading", "cycling"],
    address: {
        street: "123 Main St",
        city: "Anytown",
        coordinates: [40.7128, -74.0060]
    }
};

應用場景:

這樣的型別定義能夠靈活處理 API 回應、配置文件或嵌套資料結構。當你面對深層的嵌套物件時,遞迴型別能讓型別定義簡潔、直觀且具表現力。


小結:掌握 TypeScript 的進階技巧

📌 字串字面型別插值
透過模板字面型別,可以動態創建符合特定規則的字串型別,適合建立一致的命名規則。

📌 品牌型別的使用
使用交集型別創建品牌型別,幫助避免不同實體間的混淆,增加型別安全性。

📌 infer 提取型別
利用 infer 關鍵字,可以靈活提取型別資訊,應對複雜的函數與 Promise 操作。

📌 模板字面型別
模板字面型別結合了字串型別操作,能強制字串模式,適合 API 路徑與字串處理。

📌 遞迴型別別名
遞迴型別能表示複雜的嵌套資料結構,處理樹狀資料時非常實用。


無論今天你學到了多少新的技巧,記住程式設計的旅程是一場持續不斷的成長與探索。
每一行程式碼都是一個新的開始,無論多麼複雜的問題,只要保持學習和好奇心,總能找到答案。
擁抱挑戰,未來的你會比現在更強大!加油!🚀💪


上一篇
我推Day27 - 玩轉 TypeScript 進階映射型別,入門直接變精通
下一篇
我推Day29 - 從可變元組到 Opaque Types,揭開 TypeScript 型別系統的大心法
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言