淺談TypeScript的型別保護機制
在編寫 TS 時,它做了比我們看到的更多的事情,例如型別保護機制。讓我們編寫的程式碼更加嚴謹,至於怎麼回事,讓我們來看看吧。
由於這些機制的存在,就算你仍舊以 JS 原生的書寫方式,也能幫助你提前發現程式碼中潛在的問題。(對於認為 TS 語句更復雜的人,也能實現 0 門檻,不改變已有的習慣也能享受靜態檢測的好處。)
型別保護就是一些表示式,它們會在執行時檢查以確保在某個作用域內的型別。
為了更簡單的理解,我們首先宣告一個聯合型別用於舉例:
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 資料物件是一個具體的型別。
型別斷言實現型別保護
我需要使用 <Fish>pet 的 型別斷言,來告訴 TS 目標物件是什麼型別:
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 之外的型別(多個型別則以 聯合型別 定位)。
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: }
基於型別保護機制,在語句塊中編輯器會給予指定型別的 方法提示,以及型別檢測時會提示使用者。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。