刷完了type-challenges的所有簡單和中等難度的題目后,對TypeScript的類型操作有了一些新的理解和認識蝶怔。特此用幾篇文章來記錄下一些重要的知識點兄墅。
本系列文章需要您對TypeScript有基本的了解
基本用法
JavaScript通過Object.keys()
獲取對象的所有屬性鍵值隙咸,而typescript主要關(guān)注的是類型操作成洗,通過 keyof
操作符可以獲取對象中的所有鍵類型組成的聯(lián)合類型藏否。
為了具體了解keyof
操作符的作用,我們通過一些例子來解釋下:
type Person = {
id: number;
name: string;
age: number;
};
type P1 = keyof Person; //'id' | 'name' | 'age'
keyof
操作符得到的是Person
類型的所有鍵值類型即'id'
,'name'
和'age'
三個字面量類型組成的聯(lián)合類型'id' | 'name' | 'age'
碌燕。
實際應(yīng)用
接下來我會用一些例子講解keyof
的應(yīng)用修壕。
獲取對象所有屬性的類型
type P2 = Person[keyof Person]; // number | string
Person['key']
是查詢類型(Lookup Types), 可以獲取到對應(yīng)屬性類型的類型遏考;Person[keyof Person]
本質(zhì)上是執(zhí)行Person['id' | 'name' | 'age']
;- 由于聯(lián)合類型具有分布式的特性青团,
Person['id' | 'name' | 'age']
變成了Person['id'] | Person['name'] | Person['age']
咖楣;- 最后得到的結(jié)果就是
number | string
.
約束范型參數(shù)的范圍
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };
type P3 = MyPick<Person, 'id' | 'age'>
K extends keyof T
對K
進行了約束诱贿,只能是'id','name'珠十,'age'
中的一個類型或者幾個類型組成的聯(lián)合類型;- 如果沒有這個約束焙蹭,
{ [P in K]: T[P] }
則會報錯。
和映射類型組合實現(xiàn)某些功能
- 給對象類型的所有屬性加上
readonly
修飾符
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };
type P4 = MyReadonly<Person>; // { readonly id: number; readonly name: string; readonly age: number; }
[P in keyof T]
是對所有屬性的鍵值類型進行遍歷拯钻,案例中得到的P
分別是'id'
,'name'
和'age'
;T[P]
是查詢類型烟馅,上面介紹過了然磷,Person['id']
的結(jié)果是number
姿搜,Person['name']
的結(jié)果是string
捆憎,Person['age']
的結(jié)果是number
梭纹。- 將每個屬性類型添加
readonly
修飾符,最后的結(jié)果就是{ readonly id: number; readonly name: string; readonly age: number; }
- 去掉對象類型的某些屬性
微軟官是通過Pick
和exclude
組合來實現(xiàn)Omit
邏輯的础拨,我們可以通過以下的代碼實現(xiàn)同樣的功能绍载。
type MyOmit<T, K> = { [P in keyof T as P extends K ? never : P]: T[P] };
type P5 = MyOmit<Person, 'id' | 'name'> // {age: number;}
代碼中的
as P extends K ? never : P
這部分代碼叫做重映射 击儡,因為我們不一定需要的是P
,有些情況下需要對P
進行一些轉(zhuǎn)換蛀柴;案例中K
中包含的P
鍵值類型則通過never
忽略了矫夯,相反則保留。所以最后的結(jié)果是{age: number;}
- 給對象類型添加新的屬性
type AppendToObject<T, U extends keyof any, V> = {[P in keyof T | U]: P extends keyof T ? T[P] : V}
type P6 = AppendToObject<Person, 'address', string> // { address: string; id: number; name: string; age: number; }
和條件類型組合實現(xiàn)功能
- 兩個對象類型合并成一個新的類型
type Merge<F extends Record<string, any>, S extends Record<string, any>> = {
[P in keyof F | keyof S]: P extends keyof S ? S[P] : P extends keyof F ? F[P] : never;
};
type Skill = {
run: () => void;
}
type P7 = Merge<Person, Skill>; // { id: number; name: string; age: number; run: () => void; }
案例中
P extends keyof S 肮韧? X : Y
的部分叫做條件類型
(后面也會單獨介紹)弄企。代碼中的含義就是如果P
是F
的屬性類型区拳,則取F[P]
,如果P
是S
的屬性類型约素,則取S[P]
笆凌。
小結(jié)
經(jīng)過前面的介紹,應(yīng)該對keyof
的使用有一些感覺了送悔。下面我列一些代碼,大家可以感受下:
type _DeepPartial<T> = { [K in keyof T]?: _DeepPartial<T[K]> }
type Diff<T extends Record<string, any>, U extends Record<string, any>> = {
[P in keyof U | keyof T as P extends keyof U
? P extends keyof T
? never
: P
: P extends keyof T
? P
: never]: P extends keyof U ? U[P] : P extends keyof T ? T[P] : never;
};
這個實現(xiàn)邏輯涉及到了其他的知識點有點復(fù)雜荚藻,沒完全看懂沒關(guān)系洁段,后面會介紹祠丝。