在JS中咱們能夠經過 for...in
遍歷出一個 object{}
的全部 key 而後進行一些邏輯處理,那麼在 TS 中是否有相似的功能用於遍歷 interface{}
,在 TS2.1 版本就推出了此能力。git
它得出的結果只能賦值給類型,最簡單的書寫格式:github
{ [ K in P ] : T }
複製代碼
下面咱們對其中的 K
、P
、T
各自表示什麼,都進行詳細的說明。函數
type Coord = {
[K in 'x' | 'y']: number;
};
// 獲得
// type Coord = {
// x: number;
// y: number;
// }
複製代碼
首選肯定它執行了一個循環(能夠理解爲相似 for...in 的效果),這裏的 P 直接設置爲 'x' | 'y'
的一個聯合類型,而 K 是一個標識符,它映射爲 P 的每個子類型。T 爲數據類型,咱們直接固定爲 number,也能夠是任何其餘複雜類型。ui
由於 T 值數據類型能夠是任何值,甚至數值 1 也能夠,所以咱們把數據類設成 K 自身也行:spa
type Coord = { [K in 'x' | 'y']: K };
// 獲得 type Coord = { x: 'x'; y: 'y'; }
複製代碼
type Item = {
a: string
b: number
c: boolean
}
// Item 的全部屬性的一個 聯合類型
type ItemKeys = 'a' | 'b' | 'c';
// 也能夠簡寫爲:
// type ItemKeys = keyof Item;
type Copy = { [K in ItemKeys]: Item[K] };
// 獲得 type Copy = { a: string, b: number, c: boolean };
複製代碼
這裏的 Copy 類型與 Item 中的聲明徹底同樣,能夠簡寫爲:code
type Item = { a: string, b: number, c: boolean };
type Copy = { [K in keyof Item]: Item[K] };
// 獲得 type Copy = { a: string, b: number, c: boolean };
複製代碼
基於此特性再結合 索引訪問類型,咱們能夠封裝出一個複製效果的函數類型:繼承
type Copy<P> = { [K in keyof P]: P[K] }
type Item = { a: string, b: number, c: boolean };
type ItemCopy = Copy<Item>;
// 獲得 type ItemCopy = { a: string, b: number, c: boolean };
複製代碼
基於此特性封裝一個快速生成接口類型的函數類型:索引
type Create<P extends keyof any, T> = { [K in P]: T };
type Coord = Create<'x' | 'y', number>;
// 獲得 type Coord = { x: number, y: number };
複製代碼
若是你很眼熟,則說明你見過或用過官方預置的高級類型 Record<K extends keyof any, T>
,是的,他們如出一轍。接口
這裏的 extends
條件類型用於繼承的做用,此時咱們傳入的 聯合類型。因 P
必須可分配給 string
類型的緣由,咱們須要進行一些限制,確保接收到的 P 是有效的值。ip
而 keyof 的一個特性: keyof T
的類型會被認爲是 string
、number
、symbol
的子類型。(關於 keyof 的更多特性以後將講解)基於 keyof any
的檢測,所以下面的使用都會報錯:
type Val = Create<true, boolean>;
// Error: Type 'true' does not satisfy the constraint 'string | number | symbol'.
type Val2 = Create<() => void>;
// Error: Type '() => void' does not satisfy the constraint 'string | number | symbol'
複製代碼
還可使用 readonly
或 ?
對屬性進行設置:
type Coord = {
readonly [K in 'x' | 'y']: number
};
// 獲得
// type Coord = {
// readonly x: number;
// readonly y: number;
// };
複製代碼
兩個裝飾符也可組合使用:
type Coord = {
readonly [K in 'x' | 'y']?: number;
};
// 獲得
// type Coord = {
// readonly x?: number;
// readonly y?: number;
// };
複製代碼
但這裏面也有侷限性,沒法去除屬性上已經存在的 裝飾符:
type CoordOptional = {
x?: number;
readonly y: number;
};
type Coord = {
[K in keyof CoordOptional]: number;
};
// 獲得
// type Coord = {
// x?: number;
// readonly y: number;
// };
複製代碼
由於這個緣由,社區又在 TS2.8 又對其進行了完善,能夠在上面的裝飾符添加 -
或 +
符號:
type CoordOptional = {
x?: number;
readonly y: number;
};
type Coord = {
-readonly [K in keyof CoordOptional] -?: number;
};
// 獲得
// type Coord = {
// x: number;
// y: number;
// };
複製代碼