Quickly Uderstand TypeScript Generics

速通了解 TypeScript 泛型

前言

對於 TypeScript 的泛型🔗 我一直有種恐懼,什麼滿滿的 <T><U>extends、多層嵌套,看起來就很可怕。畢竟在日常開發裡,好像也不太需要……對吧?的確解決小問題如此,但在特定問題下泛型將會非常必要。

什麼原因需要有泛型存在?

通常在規劃可重複運用的代碼片段時會需要泛型,具體來說:

  • 某個型別要進行轉換(Utility Types🔗
  • 某個函式要接受不同資料型態的輸入……
  • 某個元件要接受不同資料型態的輸入……(Vue Generic🔗

泛型本身很簡單

泛型 = 型別版本的參數

相較於賦予函式參數具體型別過於死板:

function print(message: string): string {
return message
}
print('hi')
print(123) // Argument of type 'number' is not assignable to parameter of type 'string'

透過泛型使定義的型別更具彈性並可重複利用:

function print<MessageType>(message: MessageType): MessageType {
return message
}
print('hi') // function print<"hi">(message: "hi"): "hi"
print(123) // function print<123>(message: 123): 123

可想像 <MessageType> 泛型型別相當於透過 message 推斷而生。

extends - 泛型限制

透過關鍵字 extends 縮限泛型的可能性:

function print<MessageType extends string | number>(message: MessageType): MessageType {
return message
}
print('hi')
print(123)
print(false) // Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

相較於「名詞(A 是 string)」更類似「形容詞(A 擁有 stringnumber 特性)」。

Conditional types - 條件型別

使用類似JavaScript 條件運算子的語法基於 extends 的判斷可以轉換出不同的型別:

type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false

總結

學習泛型可用於打造更泛用的型別與程式

每次看到多層嵌套複雜的條件型別,都認真尊敬生產等級的 TypeScript 庫需要大量的心力維護和安排。

延伸閱讀