TypeScript 的 extends 條件類型

這是 TS2.8 版本中推出的特性,此能力讓類型定義變的更加靈活,須要注意:extends 運用在 type 和 class 中時徹底是兩種做用的效果。html

條件類型是一種條件表達式進行類型的關係檢測。typescript

簡單的值匹配

type Equal<X, Y> = X extends Y ? true : false;

type Num = Equal<1, 1>; // true
type Str = Equal<'a', 'a'>; // true
type Boo = Equal<true, false>; // false
複製代碼

能夠簡單理解爲一個三元表達式,固然沒有那麼簡單,讓咱們更深的扒一扒。函數

簡單的類型匹配

首先理解什麼是 」可被分配「,例以下面的這個簡單且正確的類型聲明與進行賦值:post

const num: number = 1; // 可被分配
cosnt str: string = 2; // 不可被分配
複製代碼

而條件類型的判斷邏輯,和上面的的 」可被分配「 相同邏輯:ui

type isNum<T> = T extends number ? number : string

type Num = InstanceVal<1>   // number;
type Str = InstanceVal<'1'> // string;
複製代碼

嵌套類型匹配

就像 if 語句一個道理,能夠無限嵌套。下面寫一個:根據值類型,獲取值類型名稱的函數類型(這也是官方給的例子):spa

type TypeName<T> =
    T extends string    ? "string" :
    T extends number    ? "number" :
    T extends boolean   ? "boolean" :
    T extends undefined ? "undefined" :
    T extends Function  ? "function" :
    "object";

type T0 = TypeName<string>;  // "string"
type T1 = TypeName<"a">;     // "string"
type T2 = TypeName<true>;    // "boolean"
type T3 = TypeName<() => void>;  // "function"
type T4 = TypeName<string[]>;    // "object"
複製代碼

判斷聯合類型

type A = 'x';
type B = 'x' | 'y';

type Y = A extends B ? true : false; // true
複製代碼

其中聯合類型 A 的全部子類型,在聯合類型 B 中存在,則條件知足。 若是咱們把返回值替換爲其餘的類型定義,就能根據判斷,得出想要的類型。code

當聯合類型沒法作出判斷時

咱們編寫一個 函數類型,邏輯很簡單:給的類型是 x 時返回 a 則返回 b。htm

type AB<T> = T extends 'x' ? 'a' : 'b';

type A = AB<'x'>;
// 獲得 type A = 'a'
複製代碼

看上去沒什麼問題,那是由於咱們傳入了一個明確的判斷值,確定爲 true。ip

假設咱們傳入不肯定的值,例如一個聯合類型 'x' | 'y' 會怎麼樣呢?判斷邏輯多是 true,也多是 false。其實 TypeScript 也不知道該怎麼辦,因而乎它就把兩個結果的值都返回給咱們了:get

type AB<T> = T extends 'x' ? 'a' : 'b';

type All = AB<'x' | 'y'>; // 非肯定條件,多是 'x' 或 'y'
// 獲得 type All = 'a' | 'b';
複製代碼

咱們獲得了一個 聯合類型 包含全部返回值的。

官方的解釋是:此時作了 推遲解析條件類型 的處理。

推遲解析條件類型的額外效果

在得知 條件類型不肯定時會返回全部的值 的特性狀況下,會產生一些額外的效果。

如今咱們把傳入的 T 類型也一塊兒返回,有趣的事情就發生了。且放置 T 位置不一樣,產生的效果也不一樣:

type Other = "a" | "b";
type Merge<T> = T extends "x" ? T : Other; // T 等於匹配的類型,而後加上 Other 聯合類型一塊兒返回

type Values = Merge<"x" | "y">;
// 獲得 type Values = "x" | "a" | "b";
複製代碼
type Other = "a" | "b";
type Merge<T> = T extends "x" ? Other : T; // T 等於除匹配類型的額外全部類型(官方叫候選類型)

type Values = Merge<"x" | "y">;
// 獲得 type Values = "a" | "b" | 'y';
複製代碼

經過這個特性,咱們能夠寫出 Diff<T, U> 這樣經常使用的函數類型,一個過濾功能的函數類型:

type Filter<T, U> = T extends U ? never : T;

type Values = Filter<"x" | "y" | "z", "x">;
// 獲得 type Values = "y" | "z"
複製代碼

對於 never 將單獨進行細講,這裏咱們理解爲 什麼都沒有 就行。

使用條件類型結合 映射類型 又能夠組合出不少函數類型,官網也所以預置了不少高級類型(例如:Typescript 中的 Partial, Readonly, Record, Pick),以後將會分享官方定義的全部高級類型。

條件類型還提供了 infer 推斷的能力,單獨進行講解 《TypeScript 條件類型的 infer 類型推斷能力

相關文章
相關標籤/搜索