- 類型保護(hù)(Type Guards)
- 可空類型(Nullable types)
- 類型別名(Type Aliases)
- 多態(tài)this
- 索引類型
- 映射類型
- 條件類型
- TS庫(kù)中的內(nèi)置類型轉(zhuǎn)換實(shí)用類型
1.類型保護(hù)(Type Guards)
類型保護(hù)就是確保該類型在一定的范圍內(nèi)可以運(yùn)行叫榕,簡(jiǎn)單來說就是當(dāng)一個(gè)值為number類型或者string類型怖辆,類型保護(hù)就是當(dāng)它為number類型時(shí)確保它的值為number散址,當(dāng)它為string類型時(shí)確保它的值為sting
實(shí)現(xiàn)類型保護(hù)常用的有幾下幾種方法
- in
- instanceof
- typeof
- 自定義類型
class Bird {
name: string;
constructor(name: string) {
this.name = name;
}
fly() {
console.log("fly")
}
}
class Fish {
name: string;
constructor(name: string){
this.name = name;
}
swim(){
console.log("swim")
}
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.name;
pet.swim(); //error 類型“Fish | Bird”上不存在屬性“swim”
如上充石,假如當(dāng)前pet確實(shí)是Fish類型的,我們想用到swim方法域庇,我們就可以使用類型保護(hù)來確保typescript識(shí)別他的具體類型;
注: 當(dāng)然我們可以使用類型斷言 as烁兰,但是這不是我們想要的
使用 in
if("swim" in pet){
pet.swim(); //ok
}
使用 instanceof
if(pet instanceof Fish){
pet.swim() //ok
}
使用 typeof
注: typeof 只能判斷該類型的基本類型脚囊,如"string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
function getSum(arg: number | string): number{
if(typeof arg === "number"){
return arg++
}else{
return parseInt(arg) + 1
}
}
自定義的類型保護(hù)
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
if(isFish(pet)){
pet.swim();
}
2.可空類型(Nullable types)
TypeScript有兩個(gè)特殊類型,null和undefined
let num: number | undefined = 123;
let obj: object | null = {};
// 此時(shí)求和就可以使用類型保護(hù)來避免出現(xiàn)錯(cuò)誤
function getSum(){
if(typeof num === 'number'){
num++
}
}
3. 類型別名(Type Aliases)
類型別名即為類型創(chuàng)建新名稱芦拿。比如為我們的接口數(shù)據(jù)定義一個(gè)類型Result:
type Result<T> ={
code: number;
data: T,
message: string
}
此時(shí)的Result即為類型別名
4.多態(tài)this
多態(tài)this類型是某個(gè)包含的類或接口的子類型;
this類型它能表現(xiàn)連貫接口間的繼承簡(jiǎn)易性
class Base {
constructor(
public value: number
){}
add(num: number): this{
this.value += num;
return this;
}
multiply(num: number): this {
this.value *= num;
return this;
}
}
let a = new BaseCalculator(3);
a.add(7).multiply(5).add(5).value;//鏈?zhǔn)?
使用this類型士飒,可以對(duì)其進(jìn)行擴(kuò)展查邢,并且新類可以使用舊類方法
//類可以拓展
class Child extends Base {
constructor(value: number = 0){
super(value);
}
public sin() {
this.value = Math.sin(this.value);
return this;
}
}
let b = new ScientificCalculator();
b.sin().add(1).multiply(4).value;
5.索引類型
索引類型即可被索引的類型,對(duì)應(yīng)JavaScript 中的數(shù)組酵幕、對(duì)象等聚合多個(gè)元素的類型扰藕。
keyof 為常用的索引查詢運(yùn)算符
比如: 我們想獲取某個(gè)對(duì)象中某個(gè)屬性值
function getProperty<T, K extends keyof T>(o: T, propertyName: K): T[K] {
return o[propertyName];
}
interface People {
name: string;
age: number;
say(): void;
}
let li: People = {
name: "li",
age: 18,
say(){
console.log("i am li")
}
}
const liName = getProperty(li,"name");
6.映射類型
即類型可以映射,常用于基于舊類型創(chuàng)建新類型芳撒;
TS庫(kù)中已內(nèi)置映射方法有Partial实胸,Readonly, Pick, Record
注:
Partial,Readonly, Pick為同態(tài)番官,即不會(huì)創(chuàng)建新屬性 添加新成員只能用&
Record為非同態(tài)庐完,即會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定
//將某類型全部變?yōu)榭蛇x屬性
type Partial<T> = {
[P in keyof T]?: T[P];
};
//將某類型變?yōu)閞eadonly類型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
//抽取目標(biāo)類型的子集類型
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
//非同態(tài): 會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定
type Record<K extends keyof any, T> = {
[P in K]: T;
};
//eg:
interface People{
name: string,
age: number,
sex: string
}
type PartialMan = Partial<People>;//Partial
type ReadonlyMan = Readonly<People>;//Readonly
type PickMan = Pick<People, "name" | "age">;//Pick
let PartialLilei: PartialMan = {
name: "lilei",
age: 18
}
let PickLilei: PickMan = {
name: 'lilei',
age: 18
}
//同態(tài)添加新成員只能用&
type Woman= Readonly<People> & { say(): void};
//Record
enum method {
Get= 'get',
// Post= 'post',
// Delete= 'delete'
};
interface HttpFn {
(url: string, config?: any) : Promise<void>
}
type RecordHttp = Record<method, HttpFn>;
let httpget: RecordHttp = {
get: (url: string, config?: any) => {
//return new Promise((reslove,reject) => {
//reslove()
//})
},
post:(url: string, config?: any) => {
//return new Promise((reslove,reject) => {
//reslove()
//})
}
}
7 條件類型
根據(jù)條件判斷來推測(cè)其類型。常用表達(dá)式為:
T extends U ? X : Y;
上面表達(dá)式含義為:若 T 能夠分配(賦值)給 U(即是U的子類型)徘熔,那么類型是 X门躯,否則為 Y
type value<T> = T extends boolean ? string : number;
let val: value<false> = "123";//ok
let val: value<true> = 123; //error
條件延時(shí)推測(cè)---即當(dāng)推測(cè)條件不足時(shí),會(huì)推遲條件判斷酷师,直至條件充足時(shí)讶凉;
interface Foo {
propA: boolean;
propB: boolean;
}
declare function f<T>(x: T): T extends Foo ? string : number;
function foo<U>(x: U) {
// 因?yàn)?”x“ 未知,因此判斷條件不足山孔,不能確定條件分支懂讯,推遲條件判斷直到 ”x“ 明確,
// 推遲過程中台颠,”a“ 的類型為分支條件類型組成的聯(lián)合類型褐望,string | number 聯(lián)合類型
let a = f(x);
// 這么做是完全可以的
let b: string | number = a;
}
分布條件類型
即:其中選中的類型為裸類型參數(shù)的條件類型稱為分布式條件類型;例化期間串前,分布條件類型自動(dòng)分布在聯(lián)合類型上瘫里。例如,T extends U ? X : Y
使用類型參數(shù)A | B | C
for的實(shí)例化T
解析為(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
荡碾。
注: 裸類型為 類型參數(shù)沒有被包裝在其他類型里,比如沒有被數(shù)組谨读、元組、函數(shù)坛吁、Promise,對(duì)象等包裹
如:
// 裸類型,沒有被任何其他類型包裹劳殖,即T
type NakedType<T> = T extends boolean ? "YES" : "NO"
// 非裸類型,類型參數(shù)被包裹的在元組內(nèi)拨脉,即[T]
type WrappedType<T> = [T] extends [boolean] ? "YES" : "NO";
條件類型的分布屬性可以方便地用于過濾聯(lián)合類型:
//過濾聯(lián)合類型中的null和undefined哆姻,
type NonNullable<T> = T extends null | undefined ? never : T
//never 類型表示不會(huì)是任何值,即什么都沒有
type a = string | number| Function | null | undefined;
let b: NotNullable<a> = 1;//ok
b = null; //error
條件類型與映射類型
條件類型和映射類型配合使用特別有用
//提取類型中屬性值為Funtion類型key值,相當(dāng)于 {key: key | never}[key]
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
//FunctionPropertyNames<T>為key值,Pick是提取屬性值為FunctionPropertyNames<T>的值女坑,相當(dāng)于{key: T[key]}
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;
//提取類型中屬性值不為Funtion類型key值,相當(dāng)于 {key: key | never}[key]
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];
type NonFunctionProperties<T> = Pick<T, NonFunctionPropertyNames<T>>;
interface Part {
id: number;
name: string;
subparts: Part[];
updatePart(newName: string): void;
}
type T1 = FunctionPropertyNames<Part>;
//type T1 = "updatePart"
type T2 = FunctionProperties<Part>;
// type T3 = {
// updatePart: (newName: string) => void;
// }
type T3 = NonFunctionPropertyNames<Part>;
// type T2 = "id" | "name" | "subparts"
type T4 = NonFunctionProperties<Part>;
// type T4 = {
// id: number;
// name: string;
// subparts: Part[];
// }
8 TS庫(kù)中的內(nèi)置類型轉(zhuǎn)換實(shí)用類型
1. Partial<Type> //將某類型全部變?yōu)榭蛇x屬性填具,前面已介紹
2. Readonly<Type> //將某類型全部變?yōu)镽eadonly屬性,前面已介紹
3. Pick<Type, Keys> //抽取目標(biāo)類型的子集類型,前面已介紹
3. Record<Keys,Type> //非同態(tài): 會(huì)創(chuàng)建新屬性, 新屬性由Record第一個(gè)屬性指定 劳景,前面已介紹
4. Omit<Type, Keys> //移除某一類型中的屬性
interface People{
name: string,
age: number,
sex: string,
height: number
}
type Man = Omit<People, 'height'>
/*
{ name: string,
age: number,
sex: string
}
*/
5. Exclude<Type, ExcludedUnion>//去除聯(lián)合類型中指定類型
type T0 = Exclude<"a" | "b" | "c" | "d","a" | "b">;
// type T0 = "c" | "d"誉简;
6. Extract<Type, Union>//返回聯(lián)合類型中相同類型
type T0 = Exclude<"a" | "b" | "c" | "d","a" | "f">;
// type T0 = "a";
7. NonNullable<Type>//去除類型中null和undefined盟广;
type T1 = NonNullable<string[] | string | null | undefined>;
// type T1 = string[] | string;
8. Parameters<Type>//提取函數(shù)類型中參數(shù)類型闷串,返回參數(shù)類型元祖,非函數(shù)返回unkown
type T0 = Parameters<() => string>;
// type T0 = []
type T1 = Parameters<(s: string) => void>;
// type T1 = [s: string]
type T2 = Parameters<any>;
// type T2 = unknown[]
type T3 = Parameters<never>;
// type T2 = never
9. ConstructorParameters<Type>//返回構(gòu)造函數(shù)中Constructor參數(shù)元組
type T0 = ConstructorParameters<ErrorConstructor>;
// type T0 = [message?: string]
type T1 = ConstructorParameters<FunctionConstructor>;
// type T1 = string[]
type T2 = ConstructorParameters<RegExpConstructor>;
// type T2 = [pattern: string | RegExp, flags?: string]
type T3 = ConstructorParameters<any>;
// type T3 = unknown[]
10. ReturnType<Type>//返回函數(shù)的返回類型組成的類型筋量。
type T0 = ReturnType<() => string>;
//type T0 = string
type T1 = ReturnType<(s: string) => void>;
//type T1 = void
type T2 = ReturnType<<T>() => T>;
// type T2 = unknown
11. InstanceType<Type>//返回構(gòu)造函數(shù)的實(shí)例類型組成的類型
class C {
x = 0;
y = 0;
}
type T0 = InstanceType<typeof C>;
//type T0 = C
type T1 = InstanceType<any>;
// type T1 = any
type T2 = InstanceType<never>;
//type T2 = never
12. Required<Type>//與Partial相反烹吵,將類型中可選參數(shù)變?yōu)楸剡x
interface Props {
a?: number;
b?: string;
}
const obj: Required<Props>;
//obj: {
// a: number;
// b: string;
//}
13.ThisParameterType<Type>//獲取函數(shù)中 this的數(shù)據(jù)類型,如果沒有則返回 unknown 類型
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}
14.OmitThisParameter<Type>//移除函數(shù)中的 this 數(shù)據(jù)類型:
function toHex(this: Number) {
return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
console.log(fiveToHex());
15.ThisType<Type>//該實(shí)用程序不返回轉(zhuǎn)換后的類型桨武。相反肋拔,它用作上下文this類型的標(biāo)記。請(qǐng)注意呀酸,--noImplicitThis必須啟用該標(biāo)志才能使用此實(shí)用程序
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {};
let methods: object = desc.methods || {};
return { ...data, ...methods } as D & M;
}
let obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx; // Strongly typed this
this.y += dy; // Strongly typed this
},
},
});
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
//在上面的例子中凉蜂,`methods`在參數(shù)對(duì)象`makeObject`具有上下文類型,其包括`ThisType<D & M>`和因此的類型[此](https://www.typescriptlang.org/docs/handbook/functions.html#this)內(nèi)的方法`methods`目的是`{ x: number, y: number } & { moveBy(dx: number, dy: number): number }`性誉。請(qǐng)注意窿吩,`methods`屬性的類型如何同時(shí)成為`this`方法中類型的推斷目標(biāo)和來源。
//該`ThisType<T>`標(biāo)記接口是簡(jiǎn)單地宣布一個(gè)空的接口`lib.d.ts`错览。除了在對(duì)象文字的上下文類型中被識(shí)別之外纫雁,該接口的作用類似于任何空接口。