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

華為雲開發者聯盟發表於2022-06-17
摘要:在本文中,回顧了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型別保護來解決,然而,您可以在絕對必要的時候使用自定義型別保護。

 

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

相關文章