聊聊 TypeScript 中的型別保護
在 TypeScript 中使用聯合型別時,往往會碰到這種尷尬的情況:
interface Bird {
// 獨有方法
fly();
// 共有方法
layEggs();
}
interface Fish {
// 獨有方法
swim();
// 共有方法
layEggs();
}
function getSmallPet(): Fish | Bird {
// ...
}
let pet = getSmallPet();
pet.layEggs(); // 正常
pet.swim(); // ts 報錯
如上所示,getSmallPet 函式中,既可以回傳 Fish 型別的物件,又可以回傳 Bird 型別的物件,由于回傳的物件型別不確定,所以使用聯合型別物件共有的方法時,一切正常,但是使用聯合型別物件各自獨有的方法時,ts 會報錯,
那么如何解決這個問題呢?最粗暴的方法當然是將聯合型別轉換為 any,不過這種方法不值得提倡,畢竟我們寫的是 TypeScript 而不是 AnyScript,
此時,我們使用今天的主角——型別保護,閃亮登場,它可以完美的解決這個問題,
孔乙己說過,茴香豆有四種寫法,同理,實作型別保護,也有四種寫法,
型別斷言
型別斷言是最常用的一種型別保護方法,即直接指定型別,由于,TypeScript 中識別的型別大多是靠 TypeScript 的自動型別推算算出來的,所以會出現上面所說的那種問題,即 TypeScript 不知道具體物件型別是什么,所以不確定有沒有聯合型別各自獨有的方法,
當使用型別斷言直接指定型別時,相當于你讓 TypeScript 開啟了上帝模式,可以直接知道具體型別是聯合型別中的那個,此時再使用物件的獨有方法就符合 TypeScript 的推斷了,
interface Bird {
// 獨有方法
fly();
// 共有方法
layEggs();
}
interface Fish {
// 獨有方法
swim();
// 共有方法
layEggs();
}
function getSmallPet(): Fish | Bird {
// ...
}
let pet = getSmallPet();
pet.layEggs(); // 正常
// 通過鴨子型別來進行判斷
if ((pet as Bird).fly) {
// 型別斷言
(pet as Bird).fly()
} else {
// 型別斷言
(pet as Fish).swim()
}
如果嫌棄通過 as 來進行型別斷言不夠上流,還可以使用類泛型的寫法,即:
let pet = getSmallPet();
pet.layEggs(); // 正常
// 通過鴨子型別來進行判斷
if ((<Bird>pet).fly) {
(<Bird>pet).fly()
} else {
(<Fish>pet).swim()
}
tips:友情提示,雖然使用類泛型寫法進行型別斷言看起來高端一些,但是由于在 tsx 中語法存在歧義,所以為了統一起見,推薦使用 as 的方法進行型別斷言,
in 語法
在 JS 中,我們經常使用 in 語法來判斷指定的屬性是否在指定的物件或其原型鏈中,
同理,在 TypeScript 中,我們可以通過這種方法確認物件型別,
interface Bird {
// 獨有方法
fly();
// 共有方法
layEggs();
}
interface Fish {
// 獨有方法
swim();
// 共有方法
layEggs();
}
function getSmallPet(): Fish | Bird {
// ...
}
let pet = getSmallPet();
pet.layEggs(); // 正常
// 使用 in 語法進行型別保護
if ('fly' in pet) {
pet.fly()
} else {
pet.swim()
}
原理同型別斷言一樣,都是引導 TypeScript 的型別推斷,確定物件型別,
instanceof 語法
當聯合型別中使用的是 class 而不是 interface 時,instanceof 語法就派上用場了,通過 instanceof 語法可以區分不同的 class 型別,
class Bird {
// 獨有方法
fly() {};
// 共有方法
layEggs() {};
}
class Fish {
// 獨有方法
swim() {};
// 共有方法
layEggs() {};
}
function getSmallPet(): Fish | Bird {
// ...
}
let pet = getSmallPet();
pet.layEggs(); // 正常
// 使用 in 語法進行
if (pet instanceof Bird) {
pet.fly()
} else {
pet.swim()
}
typeof 語法
typeof 語法不同于 in 語法以及 instanceof 語法,in 語法以及 instanceof 語法都是用來引導型別推斷進行不同物件型別推斷,而 typeof 語法常用于基本型別的推斷(或者是聯合使用基本型別和物件型別),
簡而言之,當使用 typeof 能夠區分聯合型別中的不同型別時,即可使用它,
function getSmallPet(): number | string {
// ...
}
let pet = getSmallPet();
if (typeof pet === 'number') {
pet++
} else {
pet = Number(pet) + 1
}
總結
就如茴香豆的四種寫法的本質依然是茴香豆一樣,型別保護的四種寫法的本質也是一樣的,即,引導 TypeScript 中的型別推斷將型別推斷的多選題變為單選題,這就是型別保護的本質,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/90143.html
標籤:JavaScript
上一篇:我終于理解了閉包
