TypeScript高級(jí)特性
關(guān)注公眾號(hào)?前端人,回復(fù)“加群”
添加無(wú)廣告學(xué)習(xí)群
Partial & Required
Partial?譯為 部分的/局部的/不完全的, 作用是將一個(gè)接口的所有參數(shù)變?yōu)榉潜靥?/section>Required?譯為必須的, 作用是將一個(gè)接口中所有非必填參數(shù) 變?yōu)楸靥睿?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">Required?的作用就是將某個(gè)類型里的屬性全部變?yōu)楸剡x項(xiàng)。
ts中的聲明
/**
?*?Make?all?properties?in?T?optional
?*/
type?Partial?=?{
??[P?in?keyof?T]?:?T[P];
};
/**
?*?Make?all?properties?in?T?required
?*/
type?Required?=?{
????[P?in?keyof?T]-?:?T[P];
};
Partial用法示例
type?Person?=?{
??name:?string;
??age:?number;
}
//?直接使用初始化所有參數(shù)都是必填
let?tom:Person?=?{
????name:?'tom',
????age:?20
};
//?使用Partial將Person中所有的參數(shù)變?yōu)榉潜靥?/span>
type?PartialPerson?=?Partial;
let?partialPerson:?PartialPerson?=?{
??name:?'tom'
};
特殊的情況
type?Person?=?{
??name:?string;
??age:?number;
??contact:?{
????email:?string;
????phone:?number;
????wechat:?string;
??}
}
type?PartialPerson?=?Partial;
//?可以看出來(lái)?第一層屬性都變成了非必填??第二層都沒(méi)變
let?partialPerson:?PartialPerson?=?{
??name:?'tom',
??contact:?{?//?error
????email:?'[email protected]'
??}
};
//?再來(lái)看看ts內(nèi)部類型的定義
/**
?*?Make?all?properties?in?T?optional
?*/
type?Partial?=?{
????[P?in?keyof?T]?:?T[P];
};
//?可以看出來(lái)并沒(méi)有考慮內(nèi)層
//?稍微改造一下
/**
?*?Make?all?properties?in?T?optional
?*/
type?DeepPartial?=?{
??[P?in?keyof?T]?:?T[P]?extends?Object???DeepPartial?:?T[P];
}
//?現(xiàn)在針對(duì)那種特殊情況就能處理了
Required 用法示例
interface?User?{
??id:?number;
??age:?number;
}
type?PartialUser?=?Partial;
//?type?PartialUser?=?{
//?????id?:?number;
//?????age?:?number;
//?}
type?PickUser?=?Required;
//?type?PickUser?=?{
//?????id:?number;
//?????age:?number;
//?}
Record
Record?譯為 記錄/記載, 作用是將一個(gè)類型的所有屬性值都映射到另一個(gè)類型上并創(chuàng)造一個(gè)新的類型
ts中的聲明
/**
?*?Construct?a?type?with?a?set?of?properties?K?of?type?T
?*/
type?Record?=?{
????[P?in?K]:?T;
};
看類型的定義就可以看出來(lái),將K中的每個(gè)屬性([P in K]),都轉(zhuǎn)為T類型, K可以是聯(lián)合類型、對(duì)象、枚舉…
type?petsGroup?=?'dog'?|?'cat'?|?'fish';
type?numOrStr?=?number?|?string;
type?IPets?=?Record;
//?type?IPets?=?{
//?????dog:?numOrStr;
//?????cat:?numOrStr;
//?????fish:?numOrStr;
//?}
Pick
Pick譯為挑選/選擇, 作用是從一個(gè)復(fù)合類型中,取出幾個(gè)想要的類型的組合一個(gè)新的類型
ts中的聲明
/**
?*?From?T,?pick?a?set?of?properties?whose?keys?are?in?the?union?K
?*/
type?Pick?=?{
??[P?in?K]:?T[P];
};
K extends keyof T的作用是約束K的key在T的key中,不能超出這個(gè)范圍,否則會(huì)報(bào)錯(cuò)的
keyof
keyof 用于獲取某種類型的所有鍵,其返回類型是聯(lián)合類型
//?keyof?用于獲取某種類型的所有鍵,其返回類型是聯(lián)合類型
interface?B?{
??id:?number;
??name:?string;
??age:?number;
}
type?B1?=?keyof?B;
//?type?B1?=?"id"?|?"name"?|?"age"
extends
這里的extends并不是用來(lái)繼承的, 而是用來(lái)限制類型
//?對(duì)象extends
type?T?=?{
??id:?number;
??name:?string;
}
type?K?=?{
??id:?number;
}
type?IType?=?K?extends?T???K?:?T;
//?type?IType?=?{
//?????id:?number;
//?????name:?string;
//?}
//?此處?K?extends?T?限制K中必須有T的所有屬性,?通俗點(diǎn)說(shuō)就是T必須是K的子集
//?聯(lián)合類型extends
type?T?=?"id"?|?"name";
type?K?=?"id";
type?IType?=?K?extends?T???K?:?T;
//?type?IType?=?"id"
//?此處限制為K必須包含于T,通俗點(diǎn)說(shuō)就是K是T的子集
使用Pick挑選屬性組成新的類型
interface?B?{
??id:?number;
??name:?string;
??age:?number;
}
type?PickB?=?Pick"id"?|?"name">;
//?type?PickB?=?{
//?????id:?number;
//?????name:?string;
//?}
Exclude
Exclude?譯為排除/不包括,?Exclude?表示從T中排除那些可分配給U的類型, 簡(jiǎn)單點(diǎn)說(shuō)就是將 T 中某些屬于 U 的類型移除掉。也可理解為取補(bǔ)集
ts中的聲明
/**
?*?Exclude?from?T?those?types?that?are?assignable?to?U
?*/
type?Exclude?=?T?extends?U???never?:?T;
例
//?例子1
type?T?=?{
??name:?string
??age:?number
}
type?U?=?{
??name:?string
}
type?IType?=?Exclude
//?type?IType?=?"age"
type?T0?=?Exclude<"a"?|?"b"?|?"c",?"a"?|?"b">
//?type?T0?=?"c"
type?T1?=?Exclude<"a"?|?"b"?|?"c",?"a"?|?"b"?|?'s'>
//?type?T1?=?"c"
Extract
Extract?譯為提取,?Extract從T中提取那些可分配給U的類型, 簡(jiǎn)單點(diǎn)說(shuō)就是提取T中,U也有的元素,也可理解為取交集
ts中的定義
/**
?*?Extract?from?T?those?types?that?are?assignable?to?U
?*/
type?Extract?=?T?extends?U???T?:?never;
例
type?T0?=?Extract<"a"?|?"b"?|?"c",?"a"?|?"f">
//?type?T0?=?"a"
type?T?=?{
??name:?string
??age:?number
}
type?U?=?{
??name:?string
}
type?IType?=?Extract
//?type?IType?=?"name"
ConstructorParameters
ConstructorParameters?譯為構(gòu)造函數(shù)參數(shù), 獲取元組中構(gòu)造函數(shù)類型的參數(shù)
ts中的聲明
/**
?*?Obtain?the?parameters?of?a?constructor?function?type?in?a?tuple
?*/
type?ConstructorParameters<T?extends?new?(...args:?any)?=>?any>?=?T?extends?new?(...args:?infer?P)?=>?any???P?:?never;
可以用來(lái)獲取類的參數(shù)類型組成的元組類型
class?People?{
??name:?string
??age:?number
??constructor(name:?string)?{
????this.name?=?name;
??}
}
type?IType?=?ConstructorParameters
//?type?IType?=?[name:?string]
//?注意這里typeof操作是取類型的作用
infer
表示在 extends 條件語(yǔ)句中待推斷的類型變量
//?例子1
//?若T是Array類型,則返回T的泛型,否則返回never類型
type?Union?=?T?extends?Array???U:?never
type?a?=?{
??name:?string
}
type?b?=?string[]
type?c??=?Union
//?type?c?=?string
type?d?=?Union
//?type?d?=?never
//?例子2
//?若T滿足(param:?infer?P)?=>?any,則返回函數(shù)入?yún)⒌念愋停駝t直接返回T
type?ParamType?=?T?extends?(param:?infer?P)?=>?any???P:?T;
?
interface?IDog?{
????name:?string;
????age:number;
}
?
type?Func?=?(dog:IDog)?=>?void;
?
type?Param?=?ParamType;?//?IDog
type?TypeString?=?ParamType?//string
理解了infer?我們?cè)诨貋?lái)看ts中ConstructorParameters?的聲明
type?ConstructorParameters<T?extends?new?(...args:?any)?=>?any>?=?T?extends?new?(...args:?infer?P)?=>?any???P?:?never;
//?T?extends?new?(...args:?any)?=>?any?首先給T加了個(gè)約束?必須滿足new?(...args:?any)?=>?any?也就是說(shuō)T必須是構(gòu)造函數(shù)類型
//?T?extends?new?(...args:?infer?P)?=>?any???P?:?never
//?T若滿足new?(...args:?any)?=>?any?則返回所有入?yún)⒌念愋??否則返回never
InstanceType
InstanceType?譯為實(shí)例類型, 用來(lái)獲取構(gòu)造函數(shù)的返回類型
ts中的定義
/**
?*?Obtain?the?return?type?of?a?constructor?function?type
?*/
type?InstanceType<T?extends?new?(...args:?any)?=>?any>?=?T?extends?new?(...args:?any)?=>?infer?R???R?:?any;
例
class?People?{
??name:?string
??age:?number
??constructor(name:?string)?{
????this.name?=?name;
??}
}
type?IType?=?InstanceType
//?type?IType?=?People
//?因?yàn)閏onstructor默認(rèn)返回this
//?constructor?People(name:?string):?People
NonNullable
NonNullable?譯為不可為空,?NonNullable從T中排除null和undefined
ts 中的定義
/**
?*?Exclude?null?and?undefined?from?T
?*/
type?NonNullable?=?T?extends?null?|?undefined???never?:?T;
例
type?example?=?NonNullable
//?type?example?=?string?|?number
Parameters & ReturnType
Parameters?用來(lái)獲取函數(shù)參數(shù)的類型ReturnType?用來(lái)獲取函數(shù)返回值類型
ts中的定義
/**
?*?Obtain?the?parameters?of?a?function?type?in?a?tuple
?*/
type?Parameters<T?extends?(...args:?any)?=>?any>?=?T?extends?(...args:?infer?P)?=>?any???P?:?never;
/**
?*?Obtain?the?return?type?of?a?function?type
?*/
type?ReturnType<T?extends?(...args:?any)?=>?any>?=?T?extends?(...args:?any)?=>?infer?R???R?:?any;
定義時(shí)寫的很明確,不過(guò)多贅述
例
type?IFoo?=?(
??uname:?string,
??uage:?number
)?=>?{
??name:?string;
??age:?number;
};
//參數(shù)類型
type?Ibar?=?Parameters;
//?type?Ibar?=?[uname:?string,?uage:?number]
type?T0?=?ReturnType;
//?type?T0?=?{
//?????name:?string;
//?????age:?number;
//?}
readonly & ReadonlyArray
readonly?只讀 被readonly?標(biāo)記的屬性只能在聲明時(shí)或類的構(gòu)造函數(shù)中賦值,之后將不可改(即只讀屬性)。ReadonlyArray?同理, 只讀數(shù)組
interface?ReadonlyArray<T>?{
????/**?Iterator?of?values?in?the?array.?*/
????[Symbol.iterator]():?IterableIterator;
????/**
?????*?Returns?an?iterable?of?key,?value?pairs?for?every?entry?in?the?array
?????*/
????entries():?IterableIterator<[number,?T]>;
????/**
?????*?Returns?an?iterable?of?keys?in?the?array
?????*/
????keys():?IterableIterator;
????/**
?????*?Returns?an?iterable?of?values?in?the?array
?????*/
????values():?IterableIterator;
}
例
interface?Person?{
??readonly?id:?number;
}
const?data:?Person?=?{
??id:?456,
};
data.id?=?789;
//?無(wú)法分配到?"id"?,因?yàn)樗侵蛔x屬性。ts(2540)
const?arr:?number[]?=?[1,?2,?3,?4];
let?ro:?ReadonlyArray?=?arr;
ro.push(444);
//?類型“readonly number[]”上不存在屬性“push”。ts(2339)
總結(jié)
ts中有很多特性都可以在lib.es5.ts中去查看, 里面定義的接口和類型非常多,主要是理解ts定義的套路,就能舉一反三,
回復(fù) 資料包領(lǐng)取我整理的進(jìn)階資料包回復(fù) 加群,加入前端進(jìn)階群console.log("點(diǎn)贊===再看===快樂(lè)")Bug離我更遠(yuǎn)了,快樂(lè)離我更近了
