当你来自Java、C++或C#等语言时,你习惯于通过抛出异常来进行错误处理。随后,在一连串的catch 子句中捕捉它们。可以说,有更好的方法来做错误处理,但这个方法已经存在了很久,考虑到历史和影响,它也已经进入了JavaScript。
所以,这是在JavaScript和TypeScript中做错误处理的有效方法。但是,尽量遵循与其他编程语言相同的流程,并在你的catch 子句中注释错误。
try {
// something with Axios, for example
} catch(e: AxiosError) {
// ^^^^^^^^^^ Error 1196 💥
}
TypeScript会出现TS1196的错误。Catch子句的变量类型注释必须是'any'或'unknown',如果指定的话。
这有几个原因。
1.任何类型都可以被抛出#
在JavaScript中,你被允许抛出每一个表达式。当然,你可以抛出 "异常"(或错误,我们在JavaScript中称之为错误),但也可以抛出任何其他值。
throw "What a weird error"; // 👍
throw 404; // 👍
throw new Error("What a weird error"); // 👍
因为任何有效的值都可以被抛出,所以可能被捕捉的值已经比你通常的子类型Error 更加广泛。
2.在JavaScript中只有一个catch子句#
JavaScript每个try 语句只有一个catch 子句。在遥远的过去,曾经有人提出过多个catch子句,甚至是条件表达式,但它们从未体现出来。
相反,你应该使用这一个catch 子句,并做instanceof 和typeof 检查(Source]。
try {
myroutine(); // There's a couple of errors thrown here
} catch (e) {
if (e instanceof TypeError) {
// A TypeError
} else if (e instanceof RangeError) {
// Handle the RangeError
} else if (e instanceof EvalError) {
// you guessed it: EvalError
} else if (typeof e === "string") {
// The error is a string
} else if (axios.isAxiosError(e)) {
// axios does an error check for us!
} else {
// everything else
logMyErrors(e);
}
}
注意:上面的例子也是TypeScript中为catch 子句缩小类型的唯一正确方法。
而且,由于所有可能的值都可以被抛出,而我们每个try 语句只有一个catch 子句来处理它们,所以e 的类型范围异常广泛。
3.任何异常都可能发生#
但是,既然你知道每一个可能发生的错误,那么一个适当的联合类型与所有可能的 "可抛物 "不是一样好用吗?在理论上,是的。在实践中,我们没有办法知道异常会有哪些类型。
在你所有的用户定义的异常和错误旁边,系统可能会在遇到类型不匹配或你的一个函数一直未定义的情况下,在内存出现问题时抛出错误。一个简单的函数调用可能会超过你的调用栈,导致臭名昭著的栈溢出。
广泛的可能值,单一的catch 子句,以及发生错误的不确定性只允许e 的两种可能类型:any 和unknown 。
那么Promise拒绝呢?#
如果你拒绝一个Promise,情况也是如此。TypeScript允许你指定的唯一东西是已完成的Promise的类型。拒绝可以以你的名义发生,也可以通过系统错误发生。
const somePromise = () => new Promise((fulfil, reject) => {
if (someConditionIsValid()) {
fulfil(42);
} else {
reject("Oh no!");
}
});
somePromise()
.then(val => console.log(val)) // val is number
.catch(e => {
console.log(e) // e can be anything, really.
})
如果你在asnyc/await 流程中调用同一个承诺,就会变得更清楚。
try {
const z = await somePromise(); // z is number
} catch(e) {
// same thing, e can be anything!
}
底线#
如果你来自其他具有类似功能的编程语言,JavaScript和TypeScript的错误处理可能是一个 "假朋友"。要意识到这些差异,相信TypeScript团队和类型检查器会给你正确的控制流,以确保你的错误处理得足够好。