日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
掌握TypeScript中的映射類型

DRY 原則(Don't repeat yourself)是軟件開發(fā)中最重要的原則之一,即不要重復(fù)自己。應(yīng)該避免在代碼中的兩個或多個地方存在重復(fù)的業(yè)務(wù)邏輯。

在 TypeScript 中,映射類型可以幫助我們避免編寫重復(fù)的代碼,它可以根據(jù)現(xiàn)有類型和定義的一些規(guī)則來創(chuàng)建新類型。下面就來看一下什么是映射類型以及如何構(gòu)建自己的映射類型。

1、基本概念

在介紹映射類型之前,先來看一些前置知識。

(1)索引訪問類型

在 TypeScript 中,我們可以通過按名稱查找屬性來訪問它的類型:

type AppConfig = {
username: string;
layout: string;
};
type Username = AppConfig["username"];

在這個例子中,通過 AppConfig? 類型的索引 username? 獲取到其類型 string,類似于在 JavaScript 中通過索引來獲取對象的屬性值。

(2)索引簽名

當(dāng)類型屬性的實(shí)際名稱是未知的,但它們將引用的數(shù)據(jù)類型已知時(shí),索引簽名就很方便。

type User = {
name: string;
preferences: {
[key: string]: string;
}
};
const currentUser: User = {
name: 'Foo Bar',
preferences: {
lang: 'en',
},
};
const currentLang = currentUser.preferences.lang;

在上面的例子中,currentLang 的類型是 string 而不是 any。此功能與 keyof 運(yùn)算符一起搭配使用是使映射類型成為可能的核心之一。

(3)聯(lián)合類型

聯(lián)合類型是兩種或多種類型的組合。它表明值的類型可以是聯(lián)合中包含的任何一種類型。

type StringOrNumberUnion = string | number;
let value: StringOrNumberUnion = 'hello, world!';
value = 100;

下面是一個更復(fù)雜的例子,編譯器可以為聯(lián)合類型提供一些高級保護(hù):

type Animal = {
name: string;
species: string;
};
type Person = {
name: string;
age: number;
};
type AnimalOrPerson = Animal | Person;
const value: AnimalOrPerson = loadFromSomewhereElse();
console.log(value.name); //
console.log(value.age); //
if ('age' in value) {
console.log(value.age); //
}

在這個例子中,因?yàn)?Animal 和 Person 都有 name 屬性,所以第 15 行的 value.name? 可以正常輸出,沒有錯誤。而第 16 行的 value.age 會編譯錯誤,因?yàn)槿绻?value 是 Animal 類型,則 value 是沒有 age 屬性的。在第 19 行的 if 塊中,因?yàn)橹挥?value 存在 age 屬性才能進(jìn)入這個代碼塊。所以,在這個 if 塊中,value 一定是 Person,TS 可以知道 value 一定是具有 age 屬性的,所以編譯正確。

(4)keyof 類型運(yùn)算符

keyof 類型運(yùn)算符返回傳遞給它的類型的 key 的聯(lián)合。

type AppConfig = {
username: string;
layout: string;
};
type AppConfigKey = keyof AppConfig;

在這個例子中,AppConfigKey? 類型會被解析為"username" | "layout"。它可以與索引簽名一起使用:

type User = {
name: string;
preferences: {
[key: string]: string;
}
};

type UserPreferenceKey = keyof User["preferences"];

這里,UserPreferenceKey? 類型被解析為 string | number。

(5)元組類型

元組是一種特殊的數(shù)組類型,其中數(shù)組的元素可能是特定索引處的特定類型。它們允許 TypeScript 編譯器圍繞值數(shù)組提供更高的安全性,尤其是當(dāng)這些值屬于不同類型時(shí)。

例如,TypeScript 編譯器能夠?yàn)樵M的各種元素提供類型安全:

type Currency = [number, string];
const amount: Currency = [100, 'USD'];
function add(values: number[]) {
return values.reduce((a, b) => a + b);
}
add(amount);
// Error: Argument of type 'Currency' is not assignable to parameter of type 'number[]'.
// Type 'string' is not assignable to type 'number'.

上面的代碼中會報(bào)錯,Currency? 類型的參數(shù)不能分配給“number[]?”類型的參數(shù),string? 類型不能分配給 number 類型。

當(dāng)訪問超出元組定義類型的索引處的元素時(shí),TypeScript 能夠進(jìn)行提示:

type LatLong = [number, number]; 
const loc: LatLong = [48.858370, 2.294481];
console.log(loc[2]);
// Error: Tuple type 'LatLong' of length '2' has no element at index '2'.

這里,元組類型 LatLong 只有兩個元素,當(dāng)試圖訪問第三個元素時(shí),就會報(bào)錯。

(6)條件類型

條件類型是一個表達(dá)式,類似于 JavaScript 中的三元表達(dá)式,其語法如下:

T extends U ? X : Y

來看一個實(shí)際的例子:

type ConditionalType = string extends boolean ? string : boolean;

在上面的示例中,ConditionalType 的類型將是 boolean,因?yàn)闂l件string extends boolean 是始終為 false。

2、映射類型

(1)初體驗(yàn)

在 TypeScript 中,當(dāng)需要從另一種類型派生(并保持同步)另一種類型時(shí),使用映射類型會特別有用。

// 用戶的配置值
type AppConfig = {
username: string;
layout: string;
};
// 用戶是否有權(quán)更改配置值
type AppPermissions = {
changeUsername: boolean;
changeLayout: boolean;
};

在上面的代碼中,AppConfig 和 AppPermissions 之間是存在隱式關(guān)系的,每當(dāng)向 AppConfig 添加新的配置值時(shí),AppPermissions 中也必須有相應(yīng)的布爾值。

這里可以使用映射類型來管理兩者之間的關(guān)系:

type AppConfig = {
username: string;
layout: string;
};
type AppPermissions = {
[Property in keyof AppConfig as `change${Capitalize}`]: boolean
};

在上面的代碼中,只要 AppConfig 中的類型發(fā)生變化,AppPermissions 就會隨之變化。實(shí)現(xiàn)了兩者之間的映射關(guān)系。

(2)概念

在 TypeScript 和 JavaScript 中,最常見的映射就是 Array.prototype.map():

[1, 2, 3].map(value => value.toString()); // ["1", "2", "3"]

這里,我們將數(shù)組中的數(shù)字映射到其字符串的表示形式。因此,TypeScript 中的映射類型意味著將一種類型轉(zhuǎn)換為另一種類型,方法就是對其每個屬性進(jìn)行轉(zhuǎn)換。

(3)實(shí)例

下面來通過一個例子來深入理解一下映射類型。對設(shè)備定義以下類型,其包含制造商和價(jià)格屬性:

type Device = {
manufacturer: string;
price: number;
};

為了讓用戶更容易理解設(shè)備信息,因此為對象添加一個新類型,該對象可以使用適當(dāng)?shù)母袷絹砀袷交O(shè)備的每個屬性:

type DeviceFormatter = {
[Key in keyof Device as `format${Capitalize}`]: (value: Device[Key]) => string;
};

我們來拆解一下上面的代碼。Key in keyof Device 使用 keyof 類型運(yùn)算符生成 Device 中所有鍵的并集。將它放在索引簽名中實(shí)際上是遍歷 Device 的所有屬性并將它們映射到 DeviceFormatter 的屬性。

format${Capitalize} 是映射的轉(zhuǎn)換部分,它使用 key 重映射和模板文字類型將屬性名稱從 x 更改為 formatX。

(value: Device[Key]) => string;? 利用索引訪問類型 Device[Key] 來指示格式化函數(shù)的 value 參數(shù)是格式化的屬性的類型。因此,formatManufacturer 接受一個 string(制造商),而 formatPrice 接受一個number(價(jià)格)。

下面是 DeviceFormatter 類型的樣子:

type DeviceFormatter = {
formatManufacturer: (value: string) => string;
formatPrice: (value: number) => string;
};

現(xiàn)在,假設(shè)將第三個屬性 releaseYear 添加到 Device 類型中:

type Device = {
manufacturer: string;
price: number;
releaseYear: number;
}

由于映射類型的強(qiáng)大功能,DeviceFormatter 類型會自動擴(kuò)展為如下類型,無需進(jìn)行任何額外的工作:

type DeviceFormatter = {
formatManufacturer: (value: string) => string;
formatPrice: (value: number) => string;
formatReleaseYear: (value: number) => string;
};

3、實(shí)用程序中的映射

TypeScript 附帶了許多用作實(shí)用程序的映射類型,最常見的包括 Omit、Partial、Readonly、Readonly、Exclude、Extract、NonNullable、ReturnType 等。下面來看看其中的兩個是如何構(gòu)建的。

(1)Partial

Partial 是一種映射類型,可以將已有的類型屬性轉(zhuǎn)換為可選類型,并通過使用與 undefined 的聯(lián)合使類型可以為空。

interface Point3D {
x: number;
y: number;
z: number;
}
type PartialPoint3D = Partial;

這里的 PartialPoint3D 類型實(shí)際是這樣的:

type PartialPoint3D = {
x?: number;
y?: number;
z?: number;
}

當(dāng)我們鼠標(biāo)懸浮在 Partial 上時(shí),就會看到它的定義:把它拿出來:

type Partial = { [P in keyof T]?: T[P] | undefined; }

下面來拆解一下這行代碼:

  • 使用泛型來傳遞目標(biāo)接口 T。
  • 使用keyof T 來獲取 T 的所有 key。
  • 通過使用[P in keyof T] 來訪問并循環(huán)所有的 key。
  • 它通過添加 ? 使 key 成為可選的。
  • 使用聯(lián)合類型T[P] | undefined 使 key 的類型可以為空。

(2)Exclude

Exclude 是一種映射類型,可讓有選擇地從類型中刪除屬性。其定義如下:

type Exclude = T extends U ? never : T

它通過使用條件類型從 T 中排除那些可分配給 U 的類型,并且在排除的屬性上返回 nerver。

type animals = 'bird' | 'cat' | 'crocodile';
type mamals = Exclude; // 'bird' | 'cat'

4、構(gòu)建映射類型

通過上面的對 TypeScript 內(nèi)置實(shí)用程序類型的原理解釋,對映射類型有了更深的理解。最后,我們來構(gòu)建一個自己的映射類型:Optional,它可以將原類型中指定 key 的類型置為可選的并且可以為空。

我們可以這樣做:

  • 將整個類型轉(zhuǎn)換為 Optional。
  • 從該新類型中僅選擇想要的屬性使其成為可選的。
  • 將原始類型與排除的屬性連接起來。

實(shí)現(xiàn)代碼及測試用例如下:

type Optional = Pick, K> & Omit;
type Person = {
name: string;
surname: string;
email: string;
}
type User = Optional;
// 現(xiàn)在 email 屬性是可選的
type AnonymousUser = Optional;
// 現(xiàn)在 email 和 surname 屬性是可選的

注意,這里使用 K extends keyof T 來確保只能傳遞屬于類型/接口的屬性。否則,TypeScript 將在編譯時(shí)拋出錯誤。

映射類型的一大優(yōu)點(diǎn)就是它們的可組合性:可以組合它們來創(chuàng)建新的映射類型。

上面使用了已有的實(shí)用程序類型實(shí)現(xiàn)了我們想要的 Optional。當(dāng)然,我們也可以在不使用任何其他映射類型的情況下重新創(chuàng)建 Optional 映射類型實(shí)用程序:

type Optional =
{ [P in K]?: T[P] }
&
{ [P in Exclude]: T[P] };

上面的代碼結(jié)合了兩種類型:

  • 第一種類型通過使用? 修飾符使 T 的所有 K 的 key 都是可選的。
  • 第二種類型通過使用Excluse來獲取剩余的key。

本文題目:掌握TypeScript中的映射類型
URL鏈接:http://www.dlmjj.cn/article/dpooioe.html