一文理解TS泛型

CodeForBetter發表於2023-04-27

當我們在編寫 TypeScript 程式碼時,經常會遇到需要通用(Generic)的情況,這時候,泛型就是我們的好幫手了。在本篇文章中,我們將深入介紹 TypeScript 泛型的概念以及如何使用。

什麼是泛型?

在程式語言中,泛型指的是引數化型別的概念。也就是說,我們可以定義一個函式、介面或類等,能夠處理不同型別的資料,而不是隻能處理一種型別的資料。這使得我們的程式碼更加靈活、通用、可複用。

下面是一個簡單的泛型函式的例子:

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

let output = identity<string>("hello world");
console.log(output); // 輸出 hello world

上面這個函式用於返回的值與傳入的引數型別相同,這類函式通常稱為 Identity 函式。這裡使用了 <T> 來代表泛型型別,在函式宣告時,我們用具體型別替換了 <T>,使得函式可以處理任意型別的資料。

泛型類

我們也可以編寫在類中使用泛型的程式碼。下面是一個簡單的例子:

class Queue<T> {
    private list: T[] = [];

    push(item: T) {
        this.list.push(item);
    }

    pop() {
        return this.list.shift();
    }
}

let queue = new Queue<string>();
queue.push("first element");
queue.push("second element");
console.log(queue.pop()); // 輸出 first element
console.log(queue.pop()); // 輸出 second element

在這個例子中,我們定義了一個 Queue 類,它使用了泛型型別 T,表示佇列中元素的型別。我們可以透過呼叫 push()pop() 方法來新增和移除元素。

泛型型別約束

有時候,我們希望泛型所代表的型別必須滿足一定的條件,這個時候我們可以透過新增型別約束來實現。下面是一個簡單例子:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

loggingIdentity("hello"); // 輸出 5

在上面的例子中,我們定義了一個泛型函式 loggingIdentity,它接受一個引數 arg,該引數的型別必須是一個具有 length 屬性的物件。我們透過 extends 關鍵字來實現型別約束。

在泛型中使用型別別名

在 TypeScript 中,我們還可以使用型別別名來定義泛型型別。下面是一個簡單的例子:

type Coordinate = [number, number];

function distance(a: Coordinate, b: Coordinate): number {
    const [x1, y1] = a;
    const [x2, y2] = b;
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}

console.log(distance([0, 0], [3, 4])); // 輸出 5

在上面的例子中,我們定義了一個型別別名 Coordinate,它是一個元組型別,包含兩個數字。然後我們定義了一個 distance 函式,它接受兩個 Coordinate 型別的引數,並計算兩點之間的距離。

總結

在本篇文章中,我們深入介紹了 TypeScript 中泛型的概念,以及提供了一些實際應用的例子。泛型是一個非常強大且常用的特性,它可以使我們的程式碼更加通用、靈活以及可複用。希望透過本篇文章的介紹,你能夠更加深入地理解 TypeScript 中的泛型。

相關文章