亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

TypeScript 條件類型

本節介紹 TypeScript 高級類型中的條件類型(conditional type),條件類型就是在初始狀態并不直接確定具體類型,而是通過一定的類型運算得到最終的變量類型。

1. 慕課解釋

條件類型用來表達非均勻類型映射,可以根據一個條件表達式來進行類型檢測,從兩個類型中選出其中一個:

T extends U ? X : Y

語義類似三目運算符:若 TU 的子類型,則類型為 X,否則類型為 Y。若無法確定 T 是否為 U 的子類型,則類型為 X | Y。

2. 示例

declare function f<T extends boolean>(x: T): T extends true ? string : number

const x = f(Math.random() < 0.5) // const x: string | number

const y = f(true) // const y: string
const z = f(false) // const z: number

代碼解釋:

第 3 行,可以看到在條件不確定的情況下,得到了聯合類型 string | number

最后兩行,條件確定時,得到了具體類型 stringnumber。

3. 可分配條件類型

在條件類型 T extends U ? X : Y 中,當泛型參數 T 取值為 A | B | C 時,這個條件類型就等價于 (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y),這就是可分配條件類型。

可分配條件類型(distributive conditional type)中被檢查的類型必須是裸類型參數(naked type parameter)。裸類型表示沒有被包裹(Wrapped) 的類型,(如:Array<T>[T]、Promise<T> 等都不是裸類型),簡而言之裸類型就是未經過任何其他類型修飾或包裝的類型。

4. 應用場景

有了這些前置知識,我們就可以分析一下 TypeScript 內置的一些工具類型,就像在映射類型中介紹的可以通過 Partial<T>,可以在項目中直接使用。

  • Exclude<T, U> – 從 T 中剔除可以賦值給 U 的類型。
  • Extract<T, U> – 提取 T 中可以賦值給 U 的類型。
  • NonNullable<T> – 從 T 中剔除 null 和 undefined。
  • ReturnType<T> – 獲取函數返回值類型。
  • InstanceType<T> – 獲取構造函數類型的實例類型。

用第一個來舉例分析:

type T00 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>  // 'b' | 'd'

來看一下 Exclude<T, U> 的實現源碼:

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

再看一個進階的例子,定義一種方法,可以取出接口類型中的函數類型:

type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>

interface Part {
  id: number
  name: string
  subparts: Part[]
  firstFn: (brand: string) => void,
  anotherFn: (channel: string) => string
}

type FnNames = FunctionPropertyNames<Part>
type FnProperties = FunctionProperties<Part>

代碼解釋:

倒數第二行,首先,遍歷整個接口,然后通過條件類型判斷接口的屬性值的類型是否是函數類型,如果是函數類型,取其屬性名。得到:

type FnNames = 'firstFn' | 'anotherFn'

倒數第一行,通過上一節介紹的工具函數 Pick,拿到這個接口的所有函數類型成員集合:

type FnProperties = {
  firstFn: (brand: string) => void
  anotherFn: (channel: string) => string
}

5. 小結

學習到了本節,可以深刻的體會到 TypeScript 中的類型不單單只是簡單的給變量進行標注,還可以通過各種運算,得到很多有趣的結果。