Typescript?轉(zhuǎn)換類型操作索引映射類型IIMT模式學(xué)習(xí)
TypeScript 新的轉(zhuǎn)換類型操作
今天學(xué)習(xí) TypeScript 的一種新的轉(zhuǎn)換類型操作:索引映射類型——IIMT(Immediately Indexed Mapped Type)
。
這個類型特別有意思,我們先看一個示例:
type Tuple = [1, true, 'false'] type List = Tuple[number]
- 上面代碼先創(chuàng)建了一個元組 Tuple。
- 然后通過 number 進行索引訪問
得到的 List 為:
type List = 1 | true | 'false'
可以發(fā)現(xiàn)上面操作 通過索引映射,將操作類型轉(zhuǎn)為了聯(lián)合類型。
如果是對象類型呢?
type Person = { name: string age: number } type GetValueType = { [K in keyof Person]: Person[K] }[keyof Person]
通過上面的轉(zhuǎn)換,我們得到一個新的類型:
type GetValueType = string | number
如果說我們想根據(jù) Person 類型創(chuàng)建一個新的類型,其結(jié)構(gòu)為:
/** * | { * key: string; * } | { * key: number; * } * */
修改 GetValueType:
type GetValueType = { [K in keyof Person]: { key: Person[K] } }[keyof Person]
上面的過程,可以分解為:
- 先創(chuàng)建一個下列結(jié)構(gòu)的類型
/** * { * name: { * key: string; * }, * age: { * key: number; * } * } */ type Temp = { [K in keyof Person]: { key: Person[K] } }
- 通過 IIMT 創(chuàng)建目標類型
type GetValueType = Temp[keyof Person]
通過上面兩個示例,可以發(fā)現(xiàn)所謂的 IIMT ,就是通過索引訪問類型操作去迭代目標類型的 key 并為每個 key 創(chuàng)建一個新的類型。
通過 IIMT 遍歷聯(lián)合類型
IIMT 的特點在于,當你遍歷聯(lián)合類型的所有成員時,同時可以為你保留整個聯(lián)合類型的上下文,不至于在遍歷過程中丟失。下面我們基于一個聯(lián)合類型創(chuàng)建一個新的聯(lián)合類型
type Fruit = "apple" | "banana" | "orange"; /** * | { * thisFruit: 'apple'; * allFruit: 'apple' | 'banana' | 'orange'; * } * | { * thisFruit: 'banana'; * allFruit: 'apple' | 'banana' | 'orange'; * } * | { * thisFruit: 'orange'; * allFruit: 'apple' | 'banana' | 'orange'; * } */ export type FruitInfo = { [F in Fruit]: { thisFruit: F; allFruit: Fruit; }; }[Fruit];
如果不使用 IIMT ,則上面會創(chuàng)建一個新的 對象類型。
我們可以看到新創(chuàng)建的 FruitInfo 類型是三個對象的聯(lián)合類型,每個對象都有一個 thisFruit 屬性和一個 allFruit 屬性。thisFruit 屬性是聯(lián)合類型的特定成員,而 allFruit 屬性是整個聯(lián)合類型。
如果再加入其他工具類型,則又可以玩出許多花活,比如我們現(xiàn)在要實現(xiàn)在 allFruit 屬性中,剔除 thisFruit,就可以這么寫:
/** * | { * thisFruit: 'apple'; * allFruit: 'banana' | 'orange'; * } * | { * thisFruit: 'banana'; * allFruit: 'apple' | 'orange'; * } * | { * thisFruit: 'orange'; * allFruit: 'apple' | 'banana'; * } */ export type FruitInfo = { [F in Fruit]: { thisFruit: F; allFruit: Exclude<Fruit, F>; }; }[Fruit];
上面的代碼在迭代 Fruit 的時候,每次都會傳入一個完整的 Fruit 類型,也就是說每次 F 每次所能感知到的 Fruit 都是獨立的、互不干擾的,所以可以使用 Exclude 從聯(lián)合類型中刪除當前的 F。
轉(zhuǎn)換對象類型的聯(lián)合類型
IIMT 經(jīng)常用于操作對象類型的聯(lián)合類型,比如需要對聯(lián)合類型中的每個對象的屬性進行修改。
比如需要對 Event 類型的每個對象類型的 type 屬性加個前綴。
type Event = | { type: "click"; x: number; y: number; } | { type: "hover"; element: HTMLElement; };
如果說想直接通過遍歷去修改聯(lián)合類型中的對象類型,那么 ts 編譯器會提示報錯,比如說像下面這樣:
type Example = { // Type 'Event' is not assignable to // type 'string | number | symbol'. [E in Event]: {}; };
因為你通過 E in Event 遍歷得到的其實是 每個對象類型,并不是 'string | number | symbol'。
這里我們可以通過 as 關(guān)鍵字在映射類型中操作類型
// 通過 Omit 剔除 type 類型,對 type 屬性單獨操作 // 通過 交叉類型實現(xiàn) 更改 type 屬性 type PrefixType<E extends { type: string }> = { type: `PREFIX_${E["type"]}`; } & Omit<E, "type">; /** * | { * type: 'PREFIX_click'; * x: number; * y: number; * } * | { * type: 'PREFIX_hover'; * element: HTMLElement; * } */ type Example = { [E in Event as E["type"]]: PrefixType<E>; }[Event["type"]];
在這里,我們插入 as E['type'] 將鍵重新映射為我們想要的類型。然后使用 PrefixType 為每個對象的 type 屬性添加前綴。
最后,我們 使用Event['type'] 索引到映射類型,也就是click | hover——這樣我們就得到了帶前綴的對象的聯(lián)合。
再看一些例子:
- 轉(zhuǎn) css 單位為聯(lián)合對象類型
type CSSUnits = "px" | "em" | "rem" | "vw" | "vh"; /** * | { * length: number; * unit: 'px'; * } * | { * length: number; * unit: 'em'; * } * | { * length: number; * unit: 'rem'; * } * | { * length: number; * unit: 'vw'; * } * | { * length: number; * unit: 'vh'; * } */ export type CSSLength = { [U in CSSUnits]: { length: number; unit: U; }; }[CSSUnits];
- 轉(zhuǎn) http 響應(yīng)碼與狀態(tài)為聯(lián)合類型
type SuccessResponseCode = 200; type ErrorResponseCode = 400 | 500; type ResponseCode = | SuccessResponseCode | ErrorResponseCode; /** * | { * code: 200; * body: { * success: true; * }; * } * | { * code: 400; * body: { * success: false; * error: string; * }; * } * | { * code: 500; * body: { * success: false; * error: string; * }; * } */ type ResponseShape = { [C in ResponseCode]: { code: C; body: C extends SuccessResponseCode ? { success: true } : { success: false; error: string }; }; }[ResponseCode]; —
總結(jié)
在 ts 中如果相對聯(lián)合類型進行遍歷操作,相較于官方文檔中提到的基礎(chǔ)操作,并不能很好的實現(xiàn)。但是 IIMT 就可以解決這個問題,相當于 typscript 通過 IIMT 提供了一個對聯(lián)合類型遍歷的能力,通過 IIMT 可以實現(xiàn)對聯(lián)合類型的單個類型進行操作,再結(jié)合其他類型體操基礎(chǔ)動作,又可以玩出許多花樣來。
參考:
- Indexed Access Types: https://www.typescriptlang.org/docs/handbook/2/indexed-access...
- Key Remapping viaas:https://www.typescriptlang.org/docs/handbook/2/mapped-types.h...
- Transform Any Union in TypeScript with the IIMT:https://www.totaltypescript.com/immediately-indexed-mapped-type
以上就是Typescript 轉(zhuǎn)換類型操作索引映射類型IIMT模式學(xué)習(xí)的詳細內(nèi)容,更多關(guān)于Typescript IIMT轉(zhuǎn)換類型的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
TS報錯Cannot?find?module?'xxx'?or?its?correspo
這篇文章主要為大家介紹了TS報錯Cannot?find?module?'xxx'?or?its?corresponding?type?declarations解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解
這篇文章主要為大家介紹了TypeScript逆變之條件推斷和泛型的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09開發(fā)typescript項目tsconfig.json配置及選項使用解析
這篇文章主要為大家介紹了tsconfig.json配置及選項使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07