在 TypeScript 處理空值異常

很是有熱情寫點說明可是,本身一直都不敢開始。有時候不知道寫什麼?有時候寫點東西怕露怯,你都工做 8 ~ 9 年了還寫這麼 low 的東西。讀了如何消除寫做過程當中的痛苦,讓寫做變成一種享受 收到鼓舞。決定把工做遇到的問題及時記錄下來。嗯,我不是個開拓者,我只是個記錄者。javascript

原由

一段時間觀察線上監控(目前咱們公司的用的是 Sentry),發現大部分錯誤是java

TypeError: Cannot read property 'xxx' of undefined
複製代碼

Cannot read property 'code' of undefined

發生這樣的錯誤,緣由其中有 2 條常常碰到:typescript

  1. 編寫代碼的時候,不注意邊界狀況,好比先後端定義數據實體字段的時候都是正常值,可是因爲一方疏忽,一個數據實體返回爲 null 或者 {}
  2. 功能迭代的過程當中,對於數據實體的結構發生變動,忽略了一些代碼,好比:定義 Staff 字段爲 Staff: { Department: {...}}, 迭代以後 Department 改爲了 Id 參照,即Staff: {Department: xxxxxxxx}

這兩種狀況在業務迅速迭代的狀況下很是常見。json

TS 以前的解決方案

原生 js 的解決方案:segmentfault

if (Staff && Staff.Department && Staff.Department.Name) {
  // your code here
}
複製代碼

除了上面 👆 的方法 lodash 提供了 get 方法來解決這個問題,get 方法的定義:後端

Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.async

根據 object 對象的 path 路徑獲取值。若是解析值是 undefined,就返回一個默認的值(defaultValue)函數

使用 get 方法上面的代碼能夠簡化成fetch

_.get(Staff, `Staff.Department.Name`, "DefaultName");
複製代碼

詳細講解請移步 ➡️ :lodash 的 get 方法jsonp

TS 的「可選鏈」 與 「空值合併」

TypeScript 3.7 推出了兩個新語言特性 可選鏈Optional Chaining)和 空值合併運算符nullish coalescing operator)更優雅地解決了這個問題。

那麼什麼是可選鏈呢?從本質上講,有了可選鏈後,咱們編寫代碼時若是遇到 null 或 undefined 就能夠當即中止某些表達式的運行。可選鏈的核心是新的 ?. 運算符,用於可選的屬性訪問。代碼能夠成

if(Staff?.Department?.Name){
  // your code here
}
複製代碼

那麼?.是否等價 &&? 答案是否認的,&& 還包含了被強制轉換成布爾值的狀況(例如空字符串、0、NaN 和 false)

可選鏈的經常使用方式

語法

可選鏈的三種「姿式」

obj?.prop       // Property access
obj?.[expr]     // Optional element access
func?.(...args) // Optional function or method call
複製代碼

用一個例子說明如何使用

type UserResponse = {
  firstName: string
  lastName: string
  age: number
  occupation?: string
  jobHistory?: {
    firstJob?: string
  },
  favoriteFoods?: string[]
}
const user: UserResponse;

// without optional chaining 🤢
const userOccupation = user && user.occupation;

// with optional chaining ❤️
const userOccupation = user?.occupation;

const userOccupation = user?.["occupation"];
// or
const favFood = user?.favoriteFoods?.[0];

複製代碼

第三種狀況:可選函數或方法調用

可選鏈式也能夠用在函數調用中。當你須要在運行時有條件地調用一個函數時,它們就會派上用場,即只有在函數存在的狀況下才會調用它。這能夠這樣實現。

const callFakeApi = async (url: string, log?: (user: object) => void ) => {
const response = await fetch(url);
  const data = await response.json();
  log?.(data);
}
callFakeApi('https://jsonplaceholder.typicode.com/todos/1', console.log);
複製代碼

空值合併

空值合併Nullish Coalescing) 是 TypeScript 3.7 中的另外一個新特性,它與 Optional Chaining 密切相關。它使用一個獨特的操做符:??,當一個表達式返回爲 nullundefined時,它做爲默認值或 "回落"值。

使用方法:

// null value
null || 20 // returns 20
null ?? 20 // returns 20

// undefined value
undefined || 20 // returns 20
undefined ?? 20 // returns 20

// boolean
true ?? 10 // returns true
false ?? 10 // returns false

// NaN
NaN ?? 20 // returns NaN

// empty string
'' ?? 5 // returns ''
複製代碼

特別注意和經常使用的||區別:?? 只對nullundefined 生效,可是 || 對強制轉換成布爾值都有效。用一個場景說明:下面這段代碼片斷嘗試從 localStorage 中讀取上次存儲的值(若是有的話);然而,由於使用了 ||,它是有 bug 的:

unction initializeAudio() {
  let volume = localStorage.volume || 0.5;
  // ...
}
複製代碼

localStorage.volume 被設成 0 時,volume 變量將被設成 0.5,這顯然不是咱們想要的結果。?? 避免了一些因假值(例如 0,NaN 以及 "")引發的一些預料以外的行爲。

參考資料

  1. lodash 的 get 方法
  2. Optional Chaining and Nullish Coalescing in TypeScript
  3. Typescript Optional Chaining
相關文章
相關標籤/搜索