一、keyof類型操作符
TypeScript中的keyof類型操作符可以獲取某個(gè)類型的所有屬性名組成的聯(lián)合類型。這個(gè)操作符的作用是幫助開發(fā)者在靜態(tài)類型檢查中更準(zhǔn)確地操作屬性名。
舉例來說,如果我們有如下一個(gè)接口:
interface Person {
name: string;
age: number;
gender: 'male' | 'female';
}
我們可以使用keyof來獲取這個(gè)接口的屬性名聯(lián)合類型:
type PersonKeys = keyof Person;
// 等價(jià)于:
// type PersonKeys = 'name' | 'age' | 'gender'
有了屬性名聯(lián)合類型,我們可以在編寫代碼時(shí)更準(zhǔn)確地操作屬性名。以下是一些使用keyof的實(shí)際應(yīng)用:
1. 動(dòng)態(tài)獲取對(duì)象的屬性值
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person: Person = { name: 'Lucy', age: 18, gender: 'female' };
const name = getProperty(person, 'name'); // 類型為string
const age = getProperty(person, 'age'); // 類型為number
const gender = getProperty(person, 'gender'); // 類型為'male' | 'female'
在這個(gè)例子中,getProperty函數(shù)的第一個(gè)參數(shù)是一個(gè)泛型類型的對(duì)象,第二個(gè)參數(shù)是對(duì)象的屬性名。由于我們使用了keyof,所以在編寫代碼時(shí)我們可以確定屬性名的類型,并且編譯器也可以在編譯時(shí)進(jìn)行類型檢查,保證我們不會(huì)誤操作屬性名或者試圖訪問不存在的屬性。
2. 限制對(duì)象的屬性種類
function createUser<Keys extends keyof Person>(name: string, value: Person[Keys]): Person {
const user: Person = { name, age: 0, gender: 'male' };
user[key] = value; // 編譯器知道key是Person的屬性名之一,不會(huì)有任何錯(cuò)誤
return user;
}
const newUser = createUser('Tom', 'male'); // 類型為Person
const errorUser = createUser('Jack', 'unknown'); // 編譯錯(cuò)誤
在這個(gè)例子中,createUser函數(shù)通過泛型限制了屬性名的類型,而屬性名的類型只能從Person的屬性名中取值。在函數(shù)內(nèi)部,我們可以安全地使用key來訪問person對(duì)象的屬性,因?yàn)閗ey的類型是Person的屬性名之一。如果我們?cè)噲D傳入一個(gè)不合法的屬性名,編譯器會(huì)及時(shí)提示錯(cuò)誤。
3. 避免硬編碼屬性名
class User {
constructor(private data: Person) {}
get<K extends keyof Person>(key: K): Person[K] {
return this.data[key];
}
}
const user = new User({ name: 'Lucy', age: 18, gender: 'female' });
const name = user.get('name'); // 類型為string
const age = user.get('age'); // 類型為number
const gender = user.get('gender'); // 類型為'male' | 'female'
在這個(gè)例子中,User類接受一個(gè)Person對(duì)象作為構(gòu)造函數(shù)的參數(shù),同時(shí)提供了一個(gè)get方法來獲取屬性值。我們使用了泛型和keyof,這樣在代碼中就不需要硬編碼屬性名,避免了潛在的錯(cuò)誤。泛型的約束可以幫助我們?cè)诰幾g時(shí)確保只能傳入合法的屬性名。
二、typeof類型操作符
TypeScript中的typeof
類型操作符可以用來獲取一個(gè)值的類型信息,它返回一個(gè)代表該值類型的字符串。typeof操作符不會(huì)運(yùn)行代碼,只會(huì)在編譯時(shí)進(jìn)行類型檢查。
使用typeof類型操作符的場(chǎng)景包括:
1. 類型檢查:可以用來檢查變量的類型。例如,可以使用typeof操作符來檢查變量是不是一個(gè)字符串。
let str = 'hello world';
if (typeof str === 'string') {
console.log('str is a string');
}
2. 類型推斷:可以使用typeof來推斷函數(shù)返回值的類型。
function double(num: number): number {
return num * 2;
}
let num = 10;
let numDouble = double(num); // numDouble的類型被推斷為number
if (typeof numDouble === 'number') {
console.log('numDouble is a number');
}
3. 編寫工具函數(shù):可以使用typeof來編寫工具函數(shù),比如判斷一個(gè)值是不是一個(gè)數(shù)組。
function isArray(value: any): value is Array<any> {
return typeof value === 'object' && value !== null && Array.isArray(value);
}
let arr = [1, 2, 3];
if (isArray(arr)) {
console.log('arr is an array');
}
4. 簡(jiǎn)化重復(fù)代碼:可以使用typeof來簡(jiǎn)化重復(fù)代碼,比如初始化一個(gè)對(duì)象中的屬性值。
interface Person {
name: string;
age: number;
}
function createPerson(name: string, age: number): Person {
return {
name,
age,
id: typeof name === 'string' ? name.slice(0, 3).toUpperCase() + age.toString() : '',
};
}
let person = createPerson('John', 30);
console.log(person.id); // JOH30
總之,typeof類型操作符在TypeScript中有很多用途,可以幫助開發(fā)者更好地編寫類型安全的代碼。
三、索引訪問類型
索引訪問類型在TypeScript中是一種用于獲取類型中屬性或元素的方式,它通過字符串或數(shù)字索引來訪問具有下標(biāo)的類型。它通常用于動(dòng)態(tài)訪問對(duì)象屬性、數(shù)組元素和元組元素等。下面我們從多個(gè)角度介紹索引訪問類型并舉例說明。
1. 動(dòng)態(tài)訪問對(duì)象屬性
假設(shè)我們有一個(gè)Person對(duì)象類型,它有兩個(gè)屬性name和age。我們可以通過索引訪問類型來動(dòng)態(tài)獲取對(duì)象的屬性值。
type Person = { name: string; age: number };
type Name = Person['name']; // string
type Age = Person['age']; // number
const person: Person = { name: 'John', age: 18 };
function getProperty(obj: Person, key: keyof Person) {
return obj[key];
}
const name: string = getProperty(person, 'name'); // 'John'
const age: number = getProperty(person, 'age'); // 18
在上述代碼中,我們定義了一個(gè)Person類型,并使用Person[‘name’]和Person[‘a(chǎn)ge’]來獲取分別獲取name和age的類型。我們使用keyof Person類型指定getProperty方法中的key參數(shù)只能傳遞Person對(duì)象的屬性名。最后我們通過getProperty方法動(dòng)態(tài)獲取person對(duì)象的屬性值。
2. 動(dòng)態(tài)訪問數(shù)組元素
索引訪問類型也可以用于動(dòng)態(tài)訪問數(shù)組元素。我們可以通過索引類型來獲取數(shù)組元素的類型,也可以通過keyof Array類型來獲取數(shù)組的索引類型。
const fruits = ['apple', 'banana', 'orange'];
type Fruit = typeof fruits[number]; // 'apple' | 'banana' | 'orange'
type Index = keyof typeof fruits; // number | "length" | "toString" | "toLocaleString" | "push" | "pop" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | "every" | "some" | "forEach" | "map" | "filter" | "reduce" | "reduceRight" | "entries" | "forEach" | "keys" | "values"
上述代碼中,我們定義了一個(gè)數(shù)組fruits,并使用typeof fruits[number]和keyof typeof fruits分別獲取了它的元素類型和索引類型。
3. 動(dòng)態(tài)訪問元組元素
元組是一種特殊的數(shù)組類型,其元素類型可以不同。我們可以通過索引訪問類型來動(dòng)態(tài)訪問元組元素。
type Tuple = [string, number];
type First = Tuple[0]; // string
type Second = Tuple[1]; // number
const tuple: Tuple = ['hello', 123];
function getTupleElement<T extends ReadonlyArray<any>, U extends keyof T>(
tuple: T,
index: U,
): T[U] {
return tuple[index];
}
const first: string = getTupleElement(tuple, 0); // 'hello'
const second: number = getTupleElement(tuple, 1); // 123
在上述代碼中,我們定義了一個(gè)元組類型Tuple,通過Tuple[0]和Tuple[1]分別獲取了它的第一個(gè)和第二個(gè)元素類型。同時(shí),我們定義了一個(gè)getTupleElement方法,使用泛型T和U分別表示元組類型和索引類型,并通過T[U]獲取元組指定索引處的元素。
總之,索引訪問類型可以用于動(dòng)態(tài)訪問對(duì)象屬性、數(shù)組元素和元組元素。它可以方便地處理動(dòng)態(tài)類型,增強(qiáng)了TypeScript的靈活性和適用性。
四、條件類型
TypeScript中的條件類型可以根據(jù)某個(gè)類型的特定屬性或條件,選擇不同的類型。條件類型是TypeScript高級(jí)類型中的一種,可以用于定義泛型的約束條件,從而增強(qiáng)代碼的類型安全性和靈活性。
下面從不同角度舉例分析說明TypeScript中的條件類型:
1. 根據(jù)屬性判斷是否可選
條件類型可以根據(jù)某個(gè)屬性是否存在或者是否可選來確定不同的類型。例如,以下代碼中,當(dāng)T中的K屬性為可選屬性時(shí),返回Partial類型;當(dāng)K為必選屬性時(shí),返回T本身:
type MyType<T, K extends keyof T> = K extends keyof T ? Partial<T> : T;
2. 根據(jù)屬性值判斷是否滿足條件
條件類型可以根據(jù)某個(gè)屬性的值是否滿足條件來確定不同的類型。例如,以下代碼中,當(dāng)T中的K屬性的類型為U時(shí),返回T本身;否則返回never類型:
type MyType<T, K extends keyof T, U> = T[K] extends U ? T : never;
3. 根據(jù)類型之間的關(guān)系判斷是否滿足條件
條件類型可以根據(jù)不同類型之間的關(guān)系來確定不同的類型。例如,以下代碼中,當(dāng)T為U的子類型時(shí),返回T本身;否則返回never類型:
type MyType<T, U> = T extends U ? T : never;
4. 根據(jù)函數(shù)參數(shù)類型判斷返回值類型
條件類型可以根據(jù)函數(shù)參數(shù)的類型來確定函數(shù)返回值類型。例如,以下代碼中,當(dāng)T為函數(shù)類型時(shí),返回函數(shù)返回值的類型;否則返回never類型:
type MyType<T> = T extends (...args: any[]) => infer R ? R : never;
5. 根據(jù)對(duì)象類型判斷是否有特定屬性
條件類型可以根據(jù)對(duì)象類型中是否含有特定屬性來確定不同的類型。例如,以下代碼中,當(dāng)T中含有名為K的屬性時(shí),返回T本身;否則返回never類型:
type MyType<T, K> = keyof T extends K ? T : never;
通過以上幾個(gè)例子,可以看出條件類型在TypeScript中的靈活性和強(qiáng)大的約束能力。條件類型可以根據(jù)不同的情況進(jìn)行不同的判斷,從而增強(qiáng)代碼的可讀性和可維護(hù)性。
五、類型推理infer
在TypeScript中,類型推理是一種自動(dòng)推斷變量類型的機(jī)制,它可以根據(jù)變量的使用上下文以及其值的類型來推斷變量的類型。而infer
關(guān)鍵字是TypeScript的一種高級(jí)類型操作符,它可以用來從已知類型中推斷出未知類型,讓類型推理更加靈活。
infer關(guān)鍵字通常在條件類型中使用,其中條件類型可以根據(jù)條件來決定返回的類型。infer用于捕獲條件類型中的未知類型,然后可以用該類型來進(jìn)行操作。下面分別從多角度舉例說明infer如何使用。
1. 從函數(shù)參數(shù)中推斷類型
在下面的這個(gè)例子中,我們可以看到如何使用infer關(guān)鍵字從函數(shù)參數(shù)中推斷出其類型:
type ParameterType<T extends (...args: any) => any> = T extends ((arg: infer P) => any) ? P : never;
function foo(param: string) {}
type ParamType = ParameterType<typeof foo>; // string
在這個(gè)例子中,我們定義了一個(gè)ParameterType類型,它接受一個(gè)函數(shù)類型作為參數(shù)。然后,我們使用infer關(guān)鍵字來推斷函數(shù)類型的參數(shù)類型,并將此類型指定為類型別名ParamType的值。
2. 從數(shù)組或元組中推斷類型
在下面的這個(gè)例子中,我們可以看到如何使用infer關(guān)鍵字從數(shù)組或元組中推斷出其類型:
type ArrayType<T> = T extends Array<infer U> ? U : never;
type TupleType<T> = T extends [infer U, ...infer V] ? [U, ...V] : never;
type A = ArrayType<number[]>; // number
type B = TupleType<[string, number, boolean]>; // [string, number, boolean]
在這個(gè)例子中,我們定義了兩個(gè)類型別名ArrayType和TupleType。ArrayType接受一個(gè)數(shù)組類型作為參數(shù),使用infer關(guān)鍵字推斷出數(shù)組元素的類型,并將其作為其返回類型。TupleType接受一個(gè)元組類型作為參數(shù),使用infer關(guān)鍵字推斷出元組中第一個(gè)元素的類型,并使用剩余類型推斷出元組剩余的元素類型。然后,我們分別將這些類型應(yīng)用于變量A和變量B,得到相應(yīng)的類型結(jié)果。
3. 從Promise中推斷類型
在下面的這個(gè)例子中,我們可以看到如何使用infer關(guān)鍵字從Promise中推斷出其類型:
type PromiseType<T> = T extends Promise<infer U> ? U : never;
async function foo(): Promise<string> {
return 'hello';
}
type FooType = PromiseType<ReturnType<typeof foo>>; // string
在這個(gè)例子中,我們定義了一個(gè)PromiseType類型,它接受一個(gè)Promise類型作為參數(shù),使用infer關(guān)鍵字推斷出Promise的值類型,并將其作為其返回類型。然后,我們定義了一個(gè)異步函數(shù)foo,其返回類型為Promise。最后,我們將函數(shù)foo的ReturnType應(yīng)用于PromiseType類型,并得到其返回值類型為string的結(jié)果。
總之,infer是TypeScript中一個(gè)非常重要的高級(jí)類型操作符,可以用于從已知類型中推斷出未知類型,讓類型推理更加靈活。通過上述多個(gè)角度的示例,希望可以更好地理解infer在TypeScript中的實(shí)際應(yīng)用。
六、分布式條件類型
分布式條件類型是TypeScript的一項(xiàng)高級(jí)特性,它也是條件類型的一種。分布式條件類型可以根據(jù)一個(gè)類型參數(shù) T,在聯(lián)合類型中判斷 T 是否為其他類型,并根據(jù) T 是該類型或其子集來生成新類型。這個(gè)生成過程會(huì)在聯(lián)合類型中遍歷每一個(gè)元素,并生成對(duì)應(yīng)的類型。與普通的條件類型不同的是,分布式條件類型會(huì)把聯(lián)合類型的操作分發(fā)到每一個(gè)元素中。
下面我們通過舉例分析,更全面地了解分布式條件類型。
1、 基本使用
首先,我們看一個(gè)最基本的例子:
type IfNumber<T> = T extends number ? 'yes' : 'no';
type A = IfNumber<1>; // 'yes'
type B = IfNumber<'a'>; // 'no'
type C = IfNumber<number | string>; // 'yes' | 'no'
這里,我們定義了一個(gè)條件類型IfNumber,當(dāng)T是number類型的時(shí)候返回’yes’,否則返回’no’。當(dāng)我們分別傳入1、‘a(chǎn)’、number | string三種類型作為類型參數(shù)進(jìn)行測(cè)試時(shí),分別返回’yes’、‘no’、‘yes’ | ‘no’。
2、 分布式條件類型在泛型中的應(yīng)用
分布式條件類型可以用在泛型中,作為泛型約束的一部分。比如,我們可以定義一個(gè)函數(shù),用于獲取對(duì)象的屬性值。如果對(duì)象的屬性值是數(shù)字,返回?cái)?shù)字類型的對(duì)象,否則返回字符串類型的對(duì)象。
type ObjectValue<T> = T extends { [key: string]: infer U } ? U : never;
type ObjectWithType<T, U> = { [K in keyof T]: ObjectValue<T[K]> extends U ? T[K] : never };
type ExtractObject<O, U> = ObjectWithType<O, U>[keyof O];
function getPropByType<O, U>(obj: O, type: U): ExtractObject<O, U>[] {
const result = [];
for (const key in obj) {
const value = obj[key];
if (typeof value === typeof type) {
result.push(value);
}
}
return result;
}
const obj = {
a: 1,
b: '2',
c: 3,
};
const result = getPropByType(obj, '2');
這里,我們使用分布式條件類型ObjectWithType來定義一個(gè)新類型ObjectWithType<T, U>,它可以將T中每個(gè)屬性值的類型做比較,只有當(dāng)屬性值的類型===U時(shí)才保留該屬性。同時(shí),我們使用ObjectValue來輔助獲取對(duì)象屬性值的類型。在getPropByType函數(shù)中,我們傳入一個(gè)對(duì)象和一個(gè)類型參數(shù)U,函數(shù)會(huì)遍歷對(duì)象的屬性值,檢查它們的類型是否等于U,并將符合條件的屬性值保存在數(shù)組中后返回。
3、 分布式條件類型在類型映射中的應(yīng)用
分布式條件類型還可以用于類型映射中。下面我們使用分布式條件類型,實(shí)現(xiàn)一個(gè)將對(duì)象中所有屬性變成可選屬性的函數(shù)。
type Optionalize<T> =
T extends any ? {
[K in keyof T]?: Optionalize<T[K]>;
} : never;
function optionalize<Key extends string, O extends { [K in Key]: any }>(obj: O): Optionalize<O> {
const result: Optionalize<O> = {};
for (const key in obj) {
const value = obj[key];
if (typeof value === 'object' && !Array.isArray(value)) {
result[key] = optionalize(value);
} else {
result[key as keyof O] = value;
}
}
return result;
}
const obj = {
a: {
b: 1,
c: {
d: 2,
},
},
e: '3',
};
const optionalObj = optionalize(obj);
這里,我們使用了分布式條件類型來定義Optionalize類型。它首先認(rèn)為T可以是任何類型,然后對(duì)于T中的每個(gè)屬性K,我們都將它變成一個(gè)可選屬性。在optionalize函數(shù)中,我們分別遍歷了obj的所有屬性,并根據(jù)value的類型決定是遞歸處理還是復(fù)制value的值到result中,最終返回了一個(gè)可選屬性合集Optionalize。文章來源:http://www.zghlxwxcb.cn/news/detail-505934.html
分布式條件類型是一項(xiàng)高級(jí)特性,它可以對(duì)聯(lián)合類型的所有元素進(jìn)行操作,生成多樣化的新類型。我們?cè)趯?shí)際場(chǎng)景中可以通過它來解決一些復(fù)雜的問題,比如提取對(duì)象中某個(gè)類型的屬性、將對(duì)象中的屬性轉(zhuǎn)換成可選屬性。掌握這個(gè)知識(shí)點(diǎn),可以讓我們更好地應(yīng)對(duì)類型轉(zhuǎn)換的挑戰(zhàn)。文章來源地址http://www.zghlxwxcb.cn/news/detail-505934.html
到了這里,關(guān)于TypeScript中的keyof、typeof、索引訪問類型、條件類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!