TypeScript 的 類型保護機制

在編寫 TS 時,它作了比咱們看到的更多的事情,例如類型保護機制。讓咱們編寫的代碼更加嚴謹,至於怎麼回事,讓咱們來看看吧。前端

因爲這些機制的存在,就算你仍舊以 JS 原生的書寫方式,也能幫助你提早發現代碼中潛在的問題。(對於認爲 TS 語句更復雜的人,也能實現 0 門檻,不改變已有的習慣也能享受靜態檢測的好處。)編輯器

類型保護就是一些表達式,它們會在運行時檢查以確保在某個做用域內的類型。函數

爲了更簡單的理解,咱們首先聲明一個聯合類型用於舉例:ui

interface Bird {
  fly(): any;
  layEggs(): any;
}

interface Fish {
  swim(): any
  layEggs(): any
}

type Pet = Bird | Fish;
複製代碼

無類型保護時報錯

function fn(pet: Pet) {  
  pet.layEggs(); // okay
  pet.swim();    // Error: Property 'swim' does not exist on type 'Bird | Fish'.
}
複製代碼

由於 TS 並不知道 pet 的實例是 Bird 仍是 Fish,所以爲了謹慎起見,在未手動聲明類型時 TS 中只能調用 聯合類型 中的 公共方法,例子中未 layEggs() 方法。除非你在調用指定對象數據的屬性或方法前,明確告訴 TS 數據對象是一個具體的類型。spa

類型斷言實現類型保護

我須要使用 <Fish>pet類型斷言,來告訴 TS 目標對象是什麼類型:code

function fn(pet: Fish | Bird) {
  if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
  } else {
    (<Bird>pet).fly();
  }
}
複製代碼

雖然這樣的斷言知足了咱們的需求,但並很差方便,須要在各處都進行引用。對象

備註:若是在編寫 tsx 時,你須要將 (<Fish>pet) 寫成 (pet as Fish),由於在 tsx 中尖括號 <> 有特殊的含義。作用域

函數中使用 is 定位類型

咱們將上面的 if 內的判斷封裝到函數中,得到更方便的類型保護方式,此函數必須使用 parameterName is Type類型謂語開發

function isFish<T>(pet: Fish | Bird): pet is Fish {
  return !!(<Fish>pet).swim;
}
複製代碼

此函數必須返回爲 boolean 類型才生效,當返回 true 時則類型定位爲 Fish ,返回 false 時則定位爲 Fish 以外的類型(多個類型則以 聯合類型 定位)。string

function fn(pet: Fish | Bird ) {  
  if (isFish(pet)) {
    pet.swim(); // 因 is 語句的生效,此語句塊中類型 let pet: Fish
  } else {
    pet.fly();  // 排除 Fish 以外的類型,此語句塊中類型 let pet: Bird
  }
}
複製代碼

須要注意是除了 if 中類型生效,TS 還能自動推斷出 else 中的類型。

就算你不使用 TS 這些特定的語句,也能享受 類型保護機制 的好處,下面讓咱們來看看。

使用 typeof 進行類型保護

若是子類型是隻是 number、string、boolean、symbol 這幾種數據類型,則能夠直接使用 typeof 關鍵字,TS 可以檢測並提供類型保護,咱們直接引用官方給的例子:

function padLeft(value, padding): string {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;   // let padding: number
    }
    else {
        return padding + value;   // let padding: string
    }
}
    
const t1 = padLeft("world", 6);        // " world"
const t2 = padLeft("world", "hello "); // "hello world"
複製代碼

使用 instanceof 進行類型保護

因爲如今前端對於 面向對象 的開發項目愈來愈多,所以類的引用也更多了。那麼類型保護用在此時,可謂是更加有重要,咱們使用 instanceof 來達到這一效果:

interface IA { x(): void; }
interface IB { y(): void; }

class A implements IA {
  x() { }
}
class B implements IB {
  y() { }
}

function fn(e: A | B) {
  if (e instanceof A)
    e.x(); // let e: A
  else
    e.y(); // let e: 
}
複製代碼

基於類型保護機制,在語句塊中編輯器會給予指定類型的 方法提示,以及類型檢測時會提示用戶。

相關文章
相關標籤/搜索