TypeScript 的映射類型 Mapped types (e.g. { [P in K]: T[P] })

在JS中咱們能夠經過 for...in 遍歷出一個 object{} 的全部 key 而後進行一些邏輯處理,那麼在 TS 中是否有相似的功能用於遍歷 interface{} ,在 TS2.1 版本就推出了此能力。git

它得出的結果只能賦值給類型,最簡單的書寫格式:github

{ [ K in P ] : T }
複製代碼

下面咱們對其中的 KPT 各自表示什麼,都進行詳細的說明。函數

利用映射類型快速建立類型

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的類型會被認爲是 stringnumbersymbol 的子類型。(關於 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;
// };

複製代碼
相關文章
相關標籤/搜索