Exploring TypeScript Type Annotations - Type Programminghtml
做者: zhilidaligithub
歡迎來到 《探索 TypeScript 類型註解》 系列教程。算法
上一篇介紹了 TS 的高級類型。 本篇將前面的知識點融會貫通,將對類型的探索提高一個層次:從類型層面進行編程。typescript
首先,咱們回顧一下前幾節對類型的探索。編程
interface
來聲明各類複雜數據類型。type
對類型進行命名。<T>
如同 JS 中函數將類型做爲參數傳遞。&
|
keyof
,T[K]
in
T extends U ? X : Y
infer
is
操做符以及上面所介紹的 typeof
根據 TS 提供的 數據類型 以及聲明的自定義類型,結合高級類型中的 操做符 能夠對類型進行各類運算 (高級類型本質上就是各類操做符表達式)。數據結構
再加上具備函數功能的 泛型,能夠對類型的運算進行封裝、複用、組合。要知道函數是 JS 中最強大的武器,誰說「類」來着,算了,好累,我還要(搬磚)拯救世界。還要知道,TS 沒有采用傳統面嚮對象語言使用的名義類型,而是基於偏向於函數式編程的結構類型,(JS 是多範式編程語言)。編程語言
到此爲止,咱們已經具有了對類型進行編程的各類工具 (程序 = 數據結構 + 算法),接下來各位童鞋就能夠發揮無窮的智慧了。函數式編程
童鞋請留步!俗話說吃人嘴短,拿人手軟,請先讓巨硬(微軟大大)炫個富。下面介紹 TypeScript 官方標準庫中封裝的實用工具類型。函數
TypeScript 提供的實用工具類型用來實現常見的類型轉換,這些類型工具函數是全局可見的。
Extract,Exclude,NonNullable
Extract<T, U>
:從 T
中提取能夠賦值給 U
的類型Exclude<T, U>
:從 T
中排除能夠賦值給 U
的類型NonNullable<T>
:從 T
中排除 null
和 undefined
使用示例
type foo = Extract<number | string, string>; // string
type bar = Exclude<number | string, string>; // number
type baz = NonNullable<number | string | null | undefined>; // string | number
複製代碼
具體實現
// 主要使用條件類型 `T extends U ? X : Y` 實現
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type NonNullable<T> = T extends null | undefined ? never : T;
複製代碼
Partial, Require, Readonly
Partial<T>
:將 T
中的全部屬性設置爲可選Require<T>
:將 T
中的全部屬性設置爲必選Readonly<T>
:將 T
中的全部屬性設置爲只讀使用示例
interface Type { a: number, b?: string };
let foo: Partial<Type> = { b: 'b' };
let bar: Required<Type> = { a: 1 }; // Error
let baz: Readonly<Type> = { a: 1 };
baz.a = 2; // Error
複製代碼
具體實現
// 主要使用映射類型 `[K in T]: Type` 及索引類型 `keyof T`、`T[P]` 實現
type Partial<T> = { [P in keyof T]?: T[P] };
type Require<T> = { [P in keyof T]-?: T[P] }; // 注意這裏的 `-?`
type Readonly<T> = { readonly [P in keyof T]: T[p] };
複製代碼
TypeScript 標準庫中提供了許多實用的工具類型,並且隨着 TypeScript 不斷更新迭代,會有更多的實用工具類型加入到標準庫中,此處不在重複介紹(提示:實用工具很實用),詳情請移步官方手冊,手冊中給出了詳細的使用示例。對於這些工具類型的具體實現,請移步官方倉庫的 lib。
在 TS 中,還能夠使用 typeof
來獲取變量的類型。
let foo: number = 3;
type bar = typeof foo; // 至關於 type bar = number
複製代碼
前面的章節中多處使用了 extends
關鍵字。以下
原生 JS 中類的繼承
class A { a: number }
class B extends A { b: string } // B 繼承 A
let a: A = new A();
let b: B = new B();
a = b; // Ok, A = B 少兼容多,子類兼容超類
複製代碼
接口繼承
interface A { a: number }
interface B extends A { b: string }
let a: A = { a: 1 };
let b: B = { b: 'b', a: 1 };
a = b; // Ok, A = B
複製代碼
泛型約束
interface A { a: number }
let foo: <B extends A>(arg: B) => void;
foo({ a: 1, b: 2});
複製代碼
條件類型
interface A { a: number }
interface B { a: number, b: string }
type E = B extends A ? true : false;
// type E = true
複製代碼
彙總以下
class SubClass extends SupClass
interface SubType extends SupType {}
<T extends U>
T extends U ? X : Y
以上均有共同的形式 Sub extends Sup
extends
關鍵字的語義:它們之間屬於繼承關係,即子類(型)繼承超類(型)。extends
用來定義,可有多個超類 Sup
,中間用 ,
分割。extends
用來檢測兼容性,即 Sup
是否兼容 Sub
既然是編程,下面從數學的角度來簡單粗略地描述 TS 類型系統,(讀者可略過,想深刻的童鞋可移步:zhuanlan.zhihu.com/p/38081852)。
TS 中的類型比如數學中的集合,類型是具備某種特定性質的 JS 值的集合。 好比 number
類型對應 JS 中全部數值的集合。
類型集合的分類
any
類型對應爲 全集。never
類型對應爲 空集。本篇主要是對類型進行編程的能力進行了梳理。
本做品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。