Typescript?轉(zhuǎn)換類(lèi)型操作索引映射類(lèi)型IIMT模式學(xué)習(xí)
TypeScript 新的轉(zhuǎn)換類(lèi)型操作
今天學(xué)習(xí) TypeScript 的一種新的轉(zhuǎn)換類(lèi)型操作:索引映射類(lèi)型——IIMT(Immediately Indexed Mapped Type)。
這個(gè)類(lèi)型特別有意思,我們先看一個(gè)示例:
type Tuple = [1, true, 'false'] type List = Tuple[number]
- 上面代碼先創(chuàng)建了一個(gè)元組 Tuple。
- 然后通過(guò) number 進(jìn)行索引訪問(wèn)
得到的 List 為:
type List = 1 | true | 'false'
可以發(fā)現(xiàn)上面操作 通過(guò)索引映射,將操作類(lèi)型轉(zhuǎn)為了聯(lián)合類(lèi)型。
如果是對(duì)象類(lèi)型呢?
type Person = {
name: string
age: number
}
type GetValueType = {
[K in keyof Person]: Person[K]
}[keyof Person]通過(guò)上面的轉(zhuǎn)換,我們得到一個(gè)新的類(lèi)型:
type GetValueType = string | number
如果說(shuō)我們想根據(jù) Person 類(lèi)型創(chuàng)建一個(gè)新的類(lèi)型,其結(jié)構(gòu)為:
/**
* | {
* key: string;
* } | {
* key: number;
* }
*
*/修改 GetValueType:
type GetValueType = {
[K in keyof Person]: {
key: Person[K]
}
}[keyof Person]上面的過(guò)程,可以分解為:
- 先創(chuàng)建一個(gè)下列結(jié)構(gòu)的類(lèi)型
/**
* {
* name: {
* key: string;
* },
* age: {
* key: number;
* }
* }
*/
type Temp = {
[K in keyof Person]: {
key: Person[K]
}
}- 通過(guò) IIMT 創(chuàng)建目標(biāo)類(lèi)型
type GetValueType = Temp[keyof Person]
通過(guò)上面兩個(gè)示例,可以發(fā)現(xiàn)所謂的 IIMT ,就是通過(guò)索引訪問(wèn)類(lèi)型操作去迭代目標(biāo)類(lèi)型的 key 并為每個(gè) key 創(chuàng)建一個(gè)新的類(lèi)型。
通過(guò) IIMT 遍歷聯(lián)合類(lèi)型
IIMT 的特點(diǎn)在于,當(dāng)你遍歷聯(lián)合類(lèi)型的所有成員時(shí),同時(shí)可以為你保留整個(gè)聯(lián)合類(lèi)型的上下文,不至于在遍歷過(guò)程中丟失。下面我們基于一個(gè)聯(lián)合類(lèi)型創(chuàng)建一個(gè)新的聯(lián)合類(lèi)型
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 ,則上面會(huì)創(chuàng)建一個(gè)新的 對(duì)象類(lèi)型。
我們可以看到新創(chuàng)建的 FruitInfo 類(lèi)型是三個(gè)對(duì)象的聯(lián)合類(lèi)型,每個(gè)對(duì)象都有一個(gè) thisFruit 屬性和一個(gè) allFruit 屬性。thisFruit 屬性是聯(lián)合類(lèi)型的特定成員,而 allFruit 屬性是整個(gè)聯(lián)合類(lèi)型。
如果再加入其他工具類(lèi)型,則又可以玩出許多花活,比如我們現(xiàn)在要實(shí)現(xiàn)在 allFruit 屬性中,剔除 thisFruit,就可以這么寫(xiě):
/**
* | {
* 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 的時(shí)候,每次都會(huì)傳入一個(gè)完整的 Fruit 類(lèi)型,也就是說(shuō)每次 F 每次所能感知到的 Fruit 都是獨(dú)立的、互不干擾的,所以可以使用 Exclude 從聯(lián)合類(lèi)型中刪除當(dāng)前的 F。
轉(zhuǎn)換對(duì)象類(lèi)型的聯(lián)合類(lèi)型
IIMT 經(jīng)常用于操作對(duì)象類(lèi)型的聯(lián)合類(lèi)型,比如需要對(duì)聯(lián)合類(lèi)型中的每個(gè)對(duì)象的屬性進(jìn)行修改。
比如需要對(duì) Event 類(lèi)型的每個(gè)對(duì)象類(lèi)型的 type 屬性加個(gè)前綴。
type Event =
| {
type: "click";
x: number;
y: number;
}
| {
type: "hover";
element: HTMLElement;
};如果說(shuō)想直接通過(guò)遍歷去修改聯(lián)合類(lèi)型中的對(duì)象類(lèi)型,那么 ts 編譯器會(huì)提示報(bào)錯(cuò),比如說(shuō)像下面這樣:
type Example = {
// Type 'Event' is not assignable to
// type 'string | number | symbol'.
[E in Event]: {};
};因?yàn)槟阃ㄟ^(guò) E in Event 遍歷得到的其實(shí)是 每個(gè)對(duì)象類(lèi)型,并不是 'string | number | symbol'。
這里我們可以通過(guò) as 關(guān)鍵字在映射類(lèi)型中操作類(lèi)型
// 通過(guò) Omit 剔除 type 類(lèi)型,對(duì) type 屬性單獨(dú)操作
// 通過(guò) 交叉類(lèi)型實(shí)現(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'] 將鍵重新映射為我們想要的類(lèi)型。然后使用 PrefixType 為每個(gè)對(duì)象的 type 屬性添加前綴。
最后,我們 使用Event['type'] 索引到映射類(lèi)型,也就是click | hover——這樣我們就得到了帶前綴的對(duì)象的聯(lián)合。
再看一些例子:
- 轉(zhuǎn) css 單位為聯(lián)合對(duì)象類(lèi)型
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)合類(lèi)型
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 中如果相對(duì)聯(lián)合類(lèi)型進(jìn)行遍歷操作,相較于官方文檔中提到的基礎(chǔ)操作,并不能很好的實(shí)現(xiàn)。但是 IIMT 就可以解決這個(gè)問(wèn)題,相當(dāng)于 typscript 通過(guò) IIMT 提供了一個(gè)對(duì)聯(lián)合類(lèi)型遍歷的能力,通過(guò) IIMT 可以實(shí)現(xiàn)對(duì)聯(lián)合類(lèi)型的單個(gè)類(lèi)型進(jìn)行操作,再結(jié)合其他類(lèi)型體操基礎(chǔ)動(dòng)作,又可以玩出許多花樣來(lái)。
參考:
- 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)換類(lèi)型操作索引映射類(lèi)型IIMT模式學(xué)習(xí)的詳細(xì)內(nèi)容,更多關(guān)于Typescript IIMT轉(zhuǎn)換類(lèi)型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ThreeJS?入門(mén)如何渲染出第一個(gè)3D圖形
這篇文章主要為大家介紹了ThreeJS?入門(mén)之如何渲染出第一個(gè)3D圖形實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
TypeScript實(shí)現(xiàn)類(lèi)型安全的EventEmitter
這篇文章主要為大家介紹了TypeScript實(shí)現(xiàn)類(lèi)型安全的EventEmitter示例詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
ts?類(lèi)型體操?Chainable?Options?可鏈?zhǔn)竭x項(xiàng)示例詳解
這篇文章主要為大家介紹了ts?類(lèi)型體操?Chainable?Options?可鏈?zhǔn)竭x項(xiàng)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
typescript?type類(lèi)型使用梳理總結(jié)
這篇文章主要為大家介紹了typescript?type類(lèi)型使用梳理總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
TypeScript手寫(xiě)一個(gè)簡(jiǎn)單的eslint插件實(shí)例
這篇文章主要為大家介紹了TypeScript手寫(xiě)一個(gè)簡(jiǎn)單的eslint插件實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
typescript快速上手的進(jìn)階類(lèi)型與技術(shù)
本文講述了typescript開(kāi)發(fā)的一些高級(jí)的類(lèi)型與技術(shù),算是對(duì)于基礎(chǔ)知識(shí)點(diǎn)的補(bǔ)充,具體內(nèi)容包括:比如元組、枚舉類(lèi)、接口、泛型相關(guān)概念等。雖說(shuō)是進(jìn)階,但是內(nèi)容不算多也并不難理解。2022-12-12
簡(jiǎn)單三行代碼函數(shù)實(shí)現(xiàn)幾十行Typescript類(lèi)型推導(dǎo)
這篇文章主要為大家介紹了簡(jiǎn)單三行代碼函數(shù)實(shí)現(xiàn)幾十行Typescript類(lèi)型推導(dǎo)的方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01

