速查手冊 – TypeScript 高級類型 cheat sheet
- 2020 年 3 月 31 日
- 筆記
溫馨提示:因微信中外鏈都無法點擊,請通過文末的」 「閱讀原文」 到技術部落格中完整查閱版;(本文整理自技術部落格)
學習 TypeScript 到一定階段,必須要學會高階類型的使用,否則一些複雜的場景若是用 any 類型來處理的話,也就失去了 TS 類型檢查的意義。
本文羅列了 TypeScript 常用的高階類型,包含 官方 、以及 常用的非官方 的高級類型聲明,該手冊直接硬啃的話有些枯燥,適合平時快速查閱,使用 Ctrl+F 來查找關鍵詞來定位即可。
- 官方文檔 – 高級類型:優先閱讀,建議閱讀英文文檔。附 中文文檔,有人做了專門的讀書筆記 Typescript學習記錄:高級類型
- TypeScript: Built-in generic types:推薦,用案例詳細解釋高階類型的使用;
- TS 一些工具泛型的使用及其實現:TS 內置工具泛型高階使用
- TypeScript 2.1 新特性一覽:查找/映射類型及 any 類型的推斷 都是在 2.1 版本引入的
- TypeScript 2.8:Exclude 等條件類型是在 2.8 版本引入的,附中文 TypeScript 2.8 引入條件類型
- lib.es2015.d.ts:大部分的聲明在這個文件中可以找到
- TypeScript 強大的類型別名:行文結構比較合理,也比較完善,可以當手冊來查
1、基礎
1.1、交叉類型
交叉類型是將 多個類型合併為一個類型。這讓我們可以把現有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性。
Person & Serializable & Loggable
- 同時是 Person 和 Serializable 和 Loggable。
- 就是說這個類型的對象同時擁有了這三種類型的成員
示例:extend 融合方法
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)
1.2、extends 關鍵字
T extends U ? X : Y
表示,如果 T 可以賦值給 U (類型兼容),則返回 X,否則返回 Y;
1.3、使用 `keyof` 和 `in`
keyof 可以用來取得一個對象介面的所有 key 值:
interface Foo { name: string; age: number } type T = keyof Foo // -> "name" | "age"
而 in 則可以遍歷枚舉類型, 例如:
type Keys = "a" | "b" type Obj = { [p in Keys]: any } // -> { a: any, b: any }
keyof 產生聯合類型, in 則可以遍歷枚舉類型, 所以他們經常一起使用。
1.4、`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、映射類型
2.1、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.2、Required(官方)
作用:將傳入的屬性變為必選項
源碼:
type Required<T> = { [P in keyof T]-?: T[P] };
解釋:
- 我們發現一個有意思的用法
-?, 這裡很好理解就是將可選項代表的?去掉, 從而讓這個類型變成必選項 - 與之對應的還有個
+?, 這個含義自然與-?之前相反, 它是用來把屬性變成可選項的
2.3、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.4、Mutable(第三方)
作用:將 T 的所有屬性的 readonly 移除
源碼:
type Mutable<T> = { -readonly [P in keyof T]: T[P] }
解釋:
- 這一對加減符號操作符
+和-, 進行的不是變數的之間的進行加減而是對readonly屬性進行加減
2.5、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.6、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、條件類型
3.1、Exclude(官方)
某些地方也稱為
Diff
作用:從 T 中剔除可以賦值給 U 的類型,換言之就是從T 中排除 U
源碼:
type Exclude<T, U> = T extends U ? never : T;
解釋:
- 在 ts 2.8 中引入了一個條件類型,
T extends U ? X : Y表示如果T是U的子類型的話,那麼就會返回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
參考文檔:
- Add support for literal type subtraction
- TypeScript在React高階組件中的使用技巧
3.2、Extract(官方)
作用:從 T 中提取出包含在 U 的類型,換言之就是從T 中提取出 U 子集
源碼:
type Extract<T, U> = T extends U ? T : never;
示例:
type T = Extract<1 | 2, 1 | 3> // -> 1
3.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.4、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.5、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、函數相關
4.1、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.2、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;
解釋:
- 使用
infer和extends條件判斷完成
示例:
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.3、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.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;
解釋:
- 使用
infer和extends條件判斷完成
示例:
function foo(x: number): Array<number> { return [x]; } type P = Parameters<typeof foo>; // -> [number]
此時 P 的真實類型就是 foo 的參數組成的元組類型 [number]
4.5、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;
解釋:
- 使用
infer和extends條件判斷完成
示例:
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 就是 Person 中 constructor 的參數 firstName 和 lastName 的類型所組成的元組類型 [string, string]。
—END—


