【速查手冊】TypeScript 高級類型 cheat sheet

學習 TypeScript 到必定階段,必需要學會高階類型的使用,不然一些複雜的場景如果用 any 類型來處理的話,也就失去了 TS 類型檢查的意義。html

本文羅列了 TypeScript 經常使用的高階類型,包含 官方 、以及 經常使用的非官方 的高級類型聲明,該手冊直接硬啃的話有些枯燥,適合平時快速查閱,使用 Ctrl+F 來查找關鍵詞來定位便可。node

一、基礎

1.一、交叉類型

交叉類型是將 多個類型合併爲一個類型。 這讓咱們能夠把現有的多種類型疊加到一塊兒成爲一種類型,它包含了所需的全部類型的特性。git

Person & Serializable & Loggable
  • 同時是 Person 和 Serializable 和 Loggable。
  • 就是說這個類型的對象同時擁有了這三種類型的成員

示例extend 融合方法github

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

特殊狀況:
T | never = T
T & never = never (which #16446 provides)typescript

1.二、extends 關鍵字

T extends U ? X : Y

表示,若是 T 能夠賦值給 U (類型兼容),則返回 X,不然返回 Y;數組

1.三、使用 keyofin

keyof 能夠用來取得一個對象接口的全部 key 值:微信

interface Foo {
  name: string;
  age: number
}
type T = keyof Foo // -> "name" | "age"

in 則能夠遍歷枚舉類型, 例如:ide

type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }

keyof 產生聯合類型, in 則能夠遍歷枚舉類型, 因此他們常常一塊兒使用。函數

1.四、infer 關鍵字

infer 這個關鍵字是在 TS 2.8 版本引入的, 在條件類型語句中,該關鍵字用於替代手動獲取類型工具

TypeScript 爲此提供了一個示例,他們建立了一個叫做 Flatten 的類型,用於將數組轉成他們須要的元素類型:

type Flatten<T> = T extends any[] ? T[number] : T;

若是使用關鍵字 infer 就能夠將上面的代碼簡化成:

type Flatten<T> = T extends Array<infer U> ? U : T;

二、映射類型

2.一、Partial(官方)

做用:將傳入的屬性變爲可選項

源碼

type Partial<T> = { [P in keyof T]?: T[P] };

解釋

  • keyof T 拿到 T 全部屬性名
  • 而後 in 進行遍歷, 將值賦給 P, 最後 T[P] 取得相應屬性的值.
  • 結合中間的 ? 咱們就明白了 Partial 的含義了.

擴展:內置的 Partial 有個侷限性,就是隻支持處理第一層的屬性,若是是嵌套多層的就沒有效果了,不過能夠以下自定義:

type PowerPartial<T> = {
    // 若是是 object,則遞歸類型
    [U in keyof T]?: T[U] extends object
      ? PowerPartial<T[U]>
      : T[U]
};

2.二、Required(官方)

做用:將傳入的屬性變爲必選項

源碼

type Required<T> = { [P in keyof T]-?: T[P] };

解釋

  • 咱們發現一個有意思的用法 -?, 這裏很好理解就是將可選項表明的 ? 去掉, 從而讓這個類型變成必選項
  • 與之對應的還有個 +? , 這個含義天然與 -? 以前相反, 它是用來把屬性變成可選項的

2.三、Readonly(官方)

做用:將傳入的屬性變爲只讀選項

源碼

type Readonly<T> = { readonly [P in keyof T]: T[P] };

擴展:在 巧用 Typescript 中,做者建立了 DeepReadonly 的聲明,使用 遞歸 的思想讓任何子屬性都不可更改

type DeepReadonly<T> = {
  readonly [P in keyof T]: DeepReadonly<T[P]>;
}

const a = { foo: { bar: 22 } }
const b = a as DeepReadonly<typeof a>
b.foo.bar = 33 // Hey, stop!

2.四、Mutable(第三方)

做用:將 T 的全部屬性的 readonly 移除

源碼

type Mutable<T> = {
  -readonly [P in keyof T]: T[P]
}

解釋

  • 這一對加減符號操做符 +-, 進行的不是變量的之間的進行加減而是對 readonly 屬性進行加減

2.五、Record(官方)

做用:將 K 中全部的屬性的值轉化爲 T 類型

源碼

type Record<K extends keyof any, T> = { [P in K]: T };

示例

// 對全部 T 類型的屬性 K, 將它轉換爲 U
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>;

const names = { foo: "hello", bar: "world", baz: "bye" };
const lengths = mapObject(names, s => s.length);  // { foo: number, bar: number, baz: number }

2.六、Pick(官方)

做用:從 T 中取出 一系列 K 的屬性

源碼

type Pick<T, K extends keyof T> = { [P in K]: T[P] };

示例

// 從 T 挑選一些屬性 K
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;

const nameAndAgeOnly = pick(person, "name", "age");  // { name: string, age: number }

三、條件類型

3.一、Exclude(官方)

某些地方也稱爲 Diff

做用:從 T 中剔除能夠賦值給 U 的類型,換言之就是從T 中排除 U

源碼

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

解釋

  • 在 ts 2.8 中引入了一個條件類型, T extends U ? X : Y 表示若是 TU 的子類型的話,那麼就會返回 X,不然返回 Y
  • 對於聯合類型來講會自動分發條件,例如 T extends U ? X : Y, T 多是 A | B 的聯合類型, 那實際狀況就變成(A extends U ? X : Y) | (B extends U ? X : Y)

示例

type T = Exclude<1 | 2, 1 | 3> // -> 2

參考文檔

3.二、Extract(官方)

做用:從 T 中提取出包含在 U 的類型,換言之就是從T 中提取出 U 子集

源碼

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

示例

type T = Extract<1 | 2, 1 | 3> // -> 1

3.三、Omit (第三方)

做用:從 T 中忽略在 K 中的屬性名 ,實現忽略對象某些屬性功能,多在高階組件中使用

源碼

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

示例

type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }

3.四、Overwrite(第三方)

做用T 中的定義被在 K 中的內容所覆蓋,多在高階組件中使用,內部藉助 Diff 操做實現

源碼

type Overwrite<T, U> = { [P in Exclude<keyof T, keyof U>]: T[P] } & U;

示例

type Item1 = { a: string, b: number, c: boolean };
type Item2 = { a: number };
type T3 = Overwrite<Item1, Item2> // { a: number, b: number, c: boolean };

3.五、ReturnType (官方)

做用:從 T 中忽略在 K 中的屬性名 ,實現忽略對象某些屬性功能,多在高階組件中使用

源碼

type ReturnType<T> = T extends (
  ...args: any[]
) => infer R
  ? R
  : any;

解釋

  • 咱們能夠用 infer 聲明一個類型變量,是用它獲取函數的返回類型,簡單說就是用它取到函數返回值的類型方便以後使用.

示例

function foo(x: number): Array<number> {
  return [x];
}
type fn = ReturnType<typeof foo>;

四、函數相關

4.一、ThisType(官方)

做用:用於指定上下文對象類型的

源碼

// node_modules/typescript/lib/lib.es5.d.ts
interface ThisType<T> { }

解釋

  • 能夠看到聲明中只有一個接口,沒有任何的實現
  • 說明這個類型是在 TS 源碼層面支持的,而不是經過類型變換。

示例

interface Person {
    name: string;
    age: number;
}

const obj: ThisType<Person> = {
  dosth() {
    this.name // string
  }
}

這樣的話,就能夠指定 obj 裏的全部方法裏的上下文對象改爲 Person 這個類型了

4.二、InstanceType(官方)

做用:用於獲取構造函數類型的實例類型

源碼

// node_modules/typescript/lib/lib.es5.d.ts

type InstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;

解釋

  • 使用 inferextends 條件判斷完成

示例

class C {
    x = 0;
    y = 0;
}

type T20 = InstanceType<typeof C>;  // C
type T21 = InstanceType<any>;  // any
type T22 = InstanceType<never>;  // any
type T23 = InstanceType<string>;  // Error
type T24 = InstanceType<Function>;  // Error

這樣的話,就能夠指定 obj 裏的全部方法裏的上下文對象改爲 Person 這個類型了

4.三、NonNullable(官方)

做用:這個類型能夠用來過濾類型中的 null 及 undefined 類型。

源碼

// node_modules/typescript/lib/lib.es5.d.ts

type NonNullable<T> = T extends null | undefined ? never : T;

解釋

  • 使用 extends 條件判斷完成

示例

type T22 = string | number | null;
type T23 = NonNullable<T22>; // -> string | number;

4.四、Parameters(官方)

做用:該類型能夠得到函數的參數類型組成的元組類型。

源碼

// node_modules/typescript/lib/lib.es5.d.ts

type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;

解釋

  • 使用 inferextends 條件判斷完成

示例

function foo(x: number): Array<number> {
  return [x];
}

type P = Parameters<typeof foo>; // -> [number]

此時 P 的真實類型就是 foo 的參數組成的元組類型 [number]

4.五、ConstructorParameters(官方)

做用:得到類的參數類型組成的元組類型。

源碼

// node_modules/typescript/lib/lib.es5.d.ts

type ConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;

解釋

  • 使用 inferextends 條件判斷完成

示例

class Person {
  private firstName: string;
  private lastName: string;
  
  constructor(firstName: string, lastName: string) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

type P = ConstructorParameters<typeof Person>; // -> [string, string]

此時 P 就是 Personconstructor 的參數 firstNamelastName 的類型所組成的元組類型 [string, string]

下面的是個人公衆號二維碼圖片,歡迎關注。
我的微信公衆號

相關文章
相關標籤/搜索