How to handle TypeScript error

如何處理 TypeScript 拋出的錯誤?

問題

JavaScript 有 try...catch 語法用於捕捉程式中的錯誤情境,在需要時使用 throw 語法來拋出「任何錯誤」,通常建議會丟出 JS 預設的錯誤物件🔗如下:

// 拋出 JS 錯誤物件
try {
throw new Error('錯誤訊息');
} catch (error) {
console.error(error.message);
}
// 拋出字串
try {
throw '錯誤訊息';
} catch (error) {
console.error(error);
}

我們要如何在 TypeScript 中正確的識別錯誤的型別呢?由於「任何錯誤」都可以被拋出,所以 TypeScript 會將 catch 接收到的錯誤物件視為 unknow,這樣會讓我們在開發時無法正確的判斷錯誤。

解方

解方一:接受錯誤為 Any

在 TypeScript 中,我們可以將 catch 接收到的錯誤物件視為 any 型別,這樣就可以接受任何型別的錯誤物件。

try {
throw new Error('錯誤訊息');
} catch (error: any) {
console.error(error.message);
}

問題是這麼做和沒用 TypeScript 一樣 😅,無法得知錯誤資訊的型別。

解方二:斷言錯誤類型

由於我們事先知道整段程式碼中只要錯誤就會拋出 Error 物件,因此可以使用 as 關鍵字來斷言捕捉到的錯誤必定是 Error 物件,這樣的作法好一點,因為我們可以確保錯誤物件也有型別。

但卻不是最佳解法,因為如果錯誤物件不是 Error 物件,程式就會拋出錯誤,我們還是可能在程式中拋出任何類型的錯誤,進而導致 Runtime Error!

try {
throw new Error('錯誤訊息');
} catch (error) {
console.error((error as Error).message);
}
// 如果我亂丟 Error 以外的東西呢? Runtime Error!
try {
throw 'Hello World';
} catch (error) {
console.error((error as Error).message);
}

最佳解法三:動態型別檢查

最佳解法是在 catch 區塊中檢查錯誤物件的型別,這樣可以確保錯誤物件的型別是正確的,我們可以透過 JS 的 instanceof🔗 語法來檢查某個值是否為其他 Class 的實例物件或建構函式 。

try {
throw new Error('錯誤訊息');
} catch (error) {
if (error instanceof Error) {
// 只有在 error 是 JS Error 物件時才會執行
console.error(error.message);
}
}

總結

非必要不使用 Any、斷言型別,動態檢測型別並基於預設錯誤物件來處理錯誤是最佳的解法。我們甚至可以基於原生錯誤物件客製化錯誤物件,這樣可以讓我們在開發時更容易的識別錯誤,不過這又是延伸的話題了,可以參考看看延伸閱讀了解更多。

延伸閱讀