TypeScript 代码整洁之道- 错误处理
将 Clean Code 的概念适用到 TypeScript,灵感来自 clean-code-javascript。
原文地址: clean-code-typescript
中文地址: clean-code-typescript
简介

这不是一份 TypeScript 设计规范,而是将 Robert C. Martin 的软件工程著作 《Clean Code》 适用到 TypeScript,指导读者使用 TypeScript 编写易读、可复用和易重构的软件。
错误处理
抛出错误是件好事!它表示着运行时已经成功识别出程序中的错误,通过停止当前堆栈上的函数执行,终止进程(在Node.js),以及在控制台中打印堆栈信息来让你知晓。
抛出Error
或 使用reject
JavaScript 和 TypeScript 允许你 throw
任何对象。Promise 也可以用任何理由对象拒绝。
建议使用 Error
类型的 throw
语法。因为你的错误可能在写有 catch
语法的高级代码中被捕获。在那里捕获字符串消息显得非常混乱,并且会使调试更加痛苦。出于同样的原因,也应该在拒绝 promise 时使用 Error
类型。
反例:
function calculateTotal(items: Item[]): number {
throw 'Not implemented.';
}
function get(): Promise<Item[]> {
return Promise.reject('Not implemented.');
}
正例:
function calculateTotal(items: Item[]): number {
throw new Error('Not implemented.');
}
function get(): Promise<Item[]> {
return Promise.reject(new Error('Not implemented.'));
}
// or equivalent to:
async function get(): Promise<Item[]> {
throw new Error('Not implemented.');
}
使用 Error
类型的好处是 try/catch/finally
语法支持它,并且隐式地所有错误都具有 stack
属性,该属性对于调试非常有用。
另外,即使不用 throw
语法而是返回自定义错误对象,TypeScript在这块更容易。考虑下面的例子:
type Failable<R, E> = {
isError: true;
error: E;
} | {
isError: false;
value: R;
}
function calculateTotal(items: Item[]): Failable<number, 'empty'> {
if (items.length === 0) {
return { isError: true, error: 'empty' };
}
// ...
return { isError: false, value: 42 };
}
详细解释请参考原文。
别忘了捕获错误
捕获错误而不处理实际上也是没有修复错误,将错误记录到控制台(console.log)也好不到哪里去,因为它常常丢失在控制台大量的日志之中。如果将代码写在try/catch
中,说明那里可能会发生错误,因此应该考虑在错误发生时做一些处理。
反例:
try {
functionThatMightThrow();
} catch (error) {
console.log(error);
}
// or even worse
try {
functionThatMightThrow();
} catch (error) {
// ignore error
}
正例:
import { logger } from './logging'
try {
functionThatMightThrow();
} catch (error) {
logger.log(error);
}
不要忽略被拒绝的 promises
理由和不能在try/catch
中忽略Error
一样。
反例:
getUser()
.then((user: User) => {
return sendEmail(user.email, 'Welcome!');
})
.catch((error) => {
console.log(error);
});
正例:
import { logger } from './logging'
getUser()
.then((user: User) => {
return sendEmail(user.email, 'Welcome!');
})
.catch((error) => {
logger.log(error);
});
// or using the async/await syntax:
try {
const user = await getUser();
await sendEmail(user.email, 'Welcome!');
} catch (error) {
logger.log(error);
}