Try   HackMD

泛用型別可以視為是將 型別化名 進行 參數化 的行為,任何型別都可以轉換成泛用型別。目的是為了讓 型別化名 能更彈性的運用。

簡單看個範例:

type Identity<T> = T;

Identity<T> 中的 T,我們視為是泛用型別 宣告時的參數,稱為型別參數(Type Parameter)

若還是很難懂,可以想成 函式 宣告時的參數 function call(T){},呼叫時可以帶入各種變數值。

function callFunction(T) { return T; } const str = 'string'; callFunction(str);

但使用泛用型別時,型別參數只能放入型別,像是 number, string 等其他篇章提及的型別。

type Identity<T> = T; let beNumber: Identity<number>;

當我們將 T 取代成 number,則 Identity<number> 的結果就會是 number

內建的泛用型別 Built-in Generics

陣列型別 - Array<T>,這是內建的泛用型別,等同於 T[]。可以想成內建已經先將陣列宣告進行型別化名。

type Array<T> = T[];

條件型別 Conditional Types

還記得我們在 <Day04:型別系統 - 明文型別 Literal Type 與 型別化名> 的最後有談過 選用屬性 嗎?

而條件型別最常見的是 Required<T> ,它可以將所有 T 中的選用屬性,轉為必要屬性。

我們用之前的範例來看:

type Member = { name: string, age: number, birthday?: Date, };

接著我們使用 Required<T>

let memberInfo: Required<Member> = { name: 'Connie', age: 18, };

若沒有使用 Required ,這段語法可以正常運作,因為 birthday 是選用屬性。但當我們使用 Required<T>,就會強制將 birthday 轉為必要屬性。

泛用化名 Generic Type Alias

除了型別(Types),函式(Function)、介面(Interface)與類別(Class),也都可轉換成泛用型式。

以型別為例,我們若將 T 帶入 boolean,但實際上屬性 name 的型別是 string,TypeScript 就會顯示警告:

type Dictionary<T> = { [prop: string]: T // 此處使用到索引型別的技巧 }; let dict: Dictionary<boolean> = { name: 'string' }

通常要針對函式做型別化名,會有一種特質,輸入參數返回值 型別一致:

type operator<T> = (p1: T, p2: T) => T;

我們也可以在宣告函式時,宣告為泛用形式:

function identityFunc<T>(params: T): T { return params; }
interface LinkedList<T> { head: LinkedListNode<T> | null; length: number; at(index: number): LinkedListNode<T> | null; }; interface LinkedListNode<T> { value: T; next: LinkedListNode<T> | null; }
class TypedArray<T> { constructor(public value: T[]) {} }

Reference


系列:跑完 JS30 就接著認識 TypeScript 入門
上一篇:Day06:型別系統 - 複合型別 Composite Types
下一篇:Day08:型別系統 - 索引型別 Indexable Types

tags: 跑完 JS30 就接著認識 TypeScript 入門
Created on ∥ March 21, 2023
文章若有任何錯誤,還請不吝給予留言指正,謝謝大家!