5種在TypeScript中使用的類型保護

摘要:在本文中,回顧了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函數返回一個Necklacebracelet對象,因為它們都實現了Accessory介面。Necklacebracelet的構造函數簽名是不同的,用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,則輸出Idtypeof類型保護符幫助我們從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

在上面的程式碼中,類型謂詞bNecklace,這會讓TypeScript將類型縮減為Necklace,而不是只返回一個布爾值。

結尾

TypeScript類型保護有助於確保類型的值,改善整體的程式碼流。在本文中,我們回顧了TypeScript中幾個最有用的類型保護,並通過幾個例子來了解它們的實際應用。

大多數時候,您的用例可以使用instanceof類型保護、tyoeof的類型保護或in類型保護來解決,然而,您可以在絕對必要的時候使用自定義類型保護。

 

點擊關注,第一時間了解華為雲新鮮技術~