摘要:在本文中,回顧了TypeScript中幾個最有用的型別保護,並通過幾個例子來了解它們的實際應用。
本文分享自華為雲社群《如何在TypeScript中使用型別保護》,作者:Ocean2022。
型別保護是一種TypeScript技術,用於獲取變數型別資訊,通常使用在條件塊語句中。型別守衛是返回布林值的常規函式,接受一個型別並告訴TypeScript是否可以縮小到更具體的型別。型別保護具有唯一的屬性,可以確保測試的值是根據返回的布林值設定的型別。
TypeScript使用了一些內建的JavaScript操作符,比如typeof、instanceof和in操作符,這些操作符用於確定一個物件是否包含屬性。型別保護可以讓你指導TypeScript編譯器在特定的上下文中推斷出變數的特定型別,確保引數的型別與你所說的一致。
型別保護通常用於縮小型別,它非常類似於特徵檢測,允許您檢測值的正確方法、原型和屬性。因此,您可以輕鬆地找出如何處理該值。
有五種主要的方式來使用型別保護:
instanceof
關鍵字typeof
關鍵字in
關鍵字- 等式收縮式保護器
- 帶有謂詞的自定義型別保護
在本文中,我們將探索上面列出的 5 種方法。讓我們開始吧!
instanceof 型別保護
Instanceof
是一個內建型別保護器,可用於檢查一個值是否是給定建構函式或類的例項。有了這個型別保護,我們可以測試一個物件或值是否派生自一個類,這對於確定例項型別的型別很有用。
instanceof
型別保護的基本語法如下:
objectVariable instanceof ClassName;
在下面的例子中,我們看到了一個instanceof
型別保護的例子:
interface Accessory { brand: string; } class Necklace implements Accessory{ kind: string; brand: string; constructor(brand: string, kind: string) { this.brand = brand; this.kind = kind; } } class bracelet implements Accessory{ brand: string; year: number; constructor(brand: string, year: number) { this.brand = brand; this.year = year; } } const getRandomAccessory = () =>{ return Math.random() < 0.5 ? new bracelet('cartier', 2021) : new Necklace('choker', 'TASAKI'); } let Accessory = getRandomAccessory(); if (Accessory instanceof bracelet) { console.log(Accessory.year); } if (Accessory instanceof Necklace) { console.log(Accessory.brand); }
上面的getRandomAccessory
函式返回一個Necklace
或bracelet
物件,因為它們都實現了Accessory
介面。Necklace
和bracelet
的建構函式簽名是不同的,用instanceof
比較兩個建構函式簽名可以有效地確定型別。
typeof 型別保護
typeof
型別保護是用來確定變數的型別。typeof
的型別保護據說是非常有限和淺薄的。它只能確定以下JavaScript能識別的型別:
- Boolean
- String
- Bigint
- Symbol
- Undefined
- Function
- Number
對於這個列表之外的任何內容,typeof型別保護只返回object。
typeof
型別保護可以用以下兩種方式編寫:
typeof v !== "typename" #or typeof v === "typename"
typename
可以是字串、數字、符號或布林值。
在下面的示例中,StudentId
有一個string|number
型別聯合引數條目。我們看到,如果變數是string
,則輸出Student
,如果是number
,則輸出Id
。typeof
型別保護符幫助我們從x
引數中提取型別:
function StudentId(x: string | number) { if (typeof x == 'string') { console.log('Student'); } if (typeof x === 'number') { console.log('Id'); } } StudentId(`446`); //prints Student StudentId(446); //prints Id
in 型別保護
in
型別保護檢查物件是否具有特定的屬性,並使用該屬性區分不同的型別。它通常返回一個布林值,表示該屬性是否存在於該物件中。它用於其縮小範圍,以及檢查瀏覽器支援。
in
型別保護的基本語法如下:
propertyName in objectName
在下面的例子中,in型別守衛檢查 house
屬性是否存在。如果存在,則返回布林值true,如果不存在,則返回false。
"house" in { name: "test", house: { parts: "door" } }; // => true "house" in { name: "test", house: { parts: "windows" } }; // => true "house" in { name: "test", house: { parts: "roof" } }; // => true "house" in { name: "test" }; // => false "house" in { name: "test", house: undefined }; // => true
下面是in
型別保護的另一個類似例子:
interface Pupil { ID: string; } interface Adult { SSN: number; } interface Person { name: string; age: number; } let person: Pupil | Adult | Person = { name: 'Britney', age: 6 }; const getIdentifier = (person: Pupil | Adult | Person) => { if ('name' in person) { return person.name; } else if ('ID' in person) { return person.ID } return person.SSN; }
等式收縮保護器
等式收縮保護器檢查表示式的值。為了使兩個變數相等,兩個變數必須是同一型別的。如果一個變數的型別未知,但它等於另一個具有精確型別的變數,那麼Typescript會使用該已知變數提供的資訊來縮小第一個變數的型別:
function getValues(a: number | string, b: string) { if(a === b) { // this is where the narrowing takes place. narrowed to string console.log(typeof a) // string } else { // if there is no narrowing, type remains unknown console.log(typeof a) // number or string } }
如果變數a
等於變數b
,那麼兩者必須具有相同的型別。在這種情況下,Typescript把它縮小到字串。如果沒有收縮,a的型別仍然不明確,因為它可以是數字或字串。
帶有謂詞的自定義型別保護
建立一個自定義型別守衛通常是使用型別守衛的強大選項。當您通過自己編寫來建立自定義型別保護時,可以檢查的內容沒有限制。但是,如果自定義型別保護被錯誤地編寫,它可能會帶來很多錯誤。因此,精度是關鍵。
一個自定義型別保護的例子如下所示:
interface Necklace{ kind: string; brand: string; } interface bracelet{ brand: string; year: number; } type Accessory = Necklace | bracelet; const isNecklace = (b: Accessory): b is Necklace => { return (b as Necklace).kind !== undefined } const Necklace: Accessory = {kind: "Choker", brand: "TASAKI"}; const bracelet: Accessory = {brand: "Cartier", year: 2021}; console.log(isNecklace(bracelet)) //Logs false console.log(isNecklace(Necklace)) //Logs true
在上面的程式碼中,型別謂詞b
是Necklace
,這會讓TypeScript將型別縮減為Necklace
,而不是隻返回一個布林值。
結尾
TypeScript型別保護有助於確保型別的值,改善整體的程式碼流。在本文中,我們回顧了TypeScript中幾個最有用的型別保護,並通過幾個例子來了解它們的實際應用。
大多數時候,您的用例可以使用instanceof
型別保護、tyoeof
的型別保護或in
型別保護來解決,然而,您可以在絕對必要的時候使用自定義型別保護。