iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
JavaScript

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

我推Day08 - 深入探索 TypeScript 高階特性

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240922/20124462jshtDutl3N.jpg


TypeScript 三大高階功能

TypeScript,除了是個 JavaScript 的強大超集之外,因為它提升了程式碼的質量和可維護,迅速成為開發者們的心頭好。

不過,很多人可能只停留在基本概念,例如類型、介面和類別的層次上。
借此機會,讓我們深入了解一些高階功能,讓我們的開發效率再度加倍提升。

在這篇文章中,我們會透過實際範例和實務應用案例,帶大家一步步了解這些功能的魅力。
我們將深入探討三個 TypeScript 的高階功能:

  • 泛型 (Generics)
  • 裝飾器 (Decorators)
  • 條件類型 (Conditional Types)

泛型 (Generics):靈活且可重複使用的程式碼

泛型允許你創建可以接受任意類型的元件,讓你的程式碼更加靈活且具重複使用性。
它特別適用於函數、類別和介面中。

  • 泛型函數

泛型函數能在保留類型安全的情況下,操作多種類型。以下是一個簡單的例子:

function identity<T>(arg: T): T {
    return arg;
}

const numberResult = identity(10); // numberResult 為 number 類型
const stringResult = identity("Hello"); // stringResult 為 string 類型

這個 identity 函數是一個泛型函數,它接受一個類型參數 T 和一個 T 類型的參數,並返回相同類型的值。這樣一來,我們就可以在不同的類型之間調用這個函數而不會喪失類型安全性。

  • 泛型類別
    泛型類別允許你為多種類型創建藍圖:
class GenericBox<T> {
    private contents: T;
    
    constructor(contents: T) {
        this.contents = contents;
    }

    getContents(): T {
        return this.contents;
    }
}

const numberBox = new GenericBox(100);
const stringBox = new GenericBox("TypeScript");

在這裡,GenericBox 是一個可以持有任意類型 T 的類別,使得該類別可以針對不同類型重複使用而無需重寫邏輯。

💡 小提醒:泛型的使用千萬不要過度,
尤其在你試圖解決的問題並不需要泛型的時候。

泛型非常適合在需要時靈活應用,但過度複雜的泛型設計往往適得其反。

  • 泛型約束
    有時,你可能想要限制泛型的類型範圍,這時就需要用到約束:
function printLength<T extends { length: number }>(arg: T): void {
    console.log(arg.length);
}

printLength("Hello"); // 有效,string 有 length 屬性
printLength([1, 2, 3]); // 有效,array 有 length 屬性

這個函數限制 T 只接受具有 length 屬性的類型,確保了類型安全性,同時仍保有泛型的靈活性。

裝飾器(Decorators):TypeScript 的元程式設計

裝飾器是一個強大的功能,可以為類別宣告和成員添加註釋和元程式設計語法。在像 Angular 和 NestJS 這樣的框架中被廣泛使用。

  • 類別裝飾器
    類別裝飾器是一個接受類別建構函數的函數,用於修改或註釋該類別:
function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class ExampleClass {
    // ...
}

這裡的 sealed 裝飾器會封裝這個類別,防止新屬性被添加到類別中。

  • 方法裝飾器
    方法裝飾器可以用來修改或註釋類別中的方法:
function log(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function (...args: any[]) {
        console.log(`Calling ${propertyName} with arguments: ${args}`);
        const result = originalMethod.apply(this, args);
        console.log(`Result: ${result}`);
        return result;
    };
}

class Calculator {
    @log
    add(a: number, b: number) {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(5, 10);

在這個例子中,log 裝飾器會記錄 add 方法的參數和結果,提供方法調用的透明度。

條件類型(Conditional Types):TypeScript 的類型邏輯

條件類型可以根據條件執行複雜的類型轉換,用於創建靈活且強大的類型定義。

  • 基本條件類型
    基本條件類型可以根據條件返回兩者之一:
type IsString<T> = T extends string ? "yes" : "no";

type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"

這裡的 IsString 會檢查 T 是否為 string 類型,若是則返回 "yes",否則返回 "no"。

  • 條件類型推斷
    條件類型還可以在條件中推斷類型:
type ElementType<T> = T extends (infer U)[] ? U : T;

type C = ElementType<number[]>; // number
type D = ElementType<string>; // string

在這個例子中,ElementType 會提取數組中的元素類型,如果不是數組則返回該類型本身。

💡 實務應用:深度唯讀(Deep Readonly)
一個實務的條件類型範例是創建深度唯讀類型,將物件的所有屬性和子屬性設為唯讀:

type DeepReadonly<T> = {
    readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

type User = {
    name: string;
    address: {
        street: string;
        city: string;
    };
};

const user: DeepReadonly<User> = {
    name: "Alice",
    address: {
        street: "123 Main St",
        city: "Wonderland",
    },
};

// user.address.street = "456 Side St"; // 這樣的修改會報錯

DeepReadonly 會遞迴地將 User 的所有屬性設為唯讀(Readonly),確保物件的不可變性。


總結

  1. 泛型 (Generics)

    • 提供靈活性和重複使用性,適用於函數、類別和介面中。
    • 可在保留類型安全的前提下操作多種類型。
    • 約束泛型的類型範圍以保證類型安全性。
  2. 裝飾器 (Decorators)

    • 增強元程式設計能力,用於類別和方法的註釋與修改。
    • 常見於框架如 Angular 和 NestJS 中。
    • 幫助追蹤方法調用,增強程式碼的透明度。
  3. 條件類型 (Conditional Types)

    • 透過條件邏輯實現複雜的類型轉換和推斷。
    • 適用於靈活且強大的類型定義。
    • 深度唯讀(Deep Readonly)是其中一個實務應用,確保物件的不可變性。
  4. 應用這些特性的好處

    • 提升程式碼質量和可維護性。
    • 適用於各類型專案,從簡單工具到複雜應用。
    • 寫出更優雅且穩健的 TypeScript 程式碼。

在你的專案裡快來試試看這些高階特性吧~✨保證會讓你的開發流程大大升級,變得更有趣喔!😆🚀💡


上一篇
我推Day07 - 驚!TypeScript 搜尋功能踩雷全紀錄:5 大常見錯誤你一定中過!
下一篇
我推Day09 - 用 TypeScript 型別守護我們的技術派對!
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言