受this篇文章的启发,我现在使用了一个返回错误而不是抛出错误的模式(就像在Golang或FP-TS中一样).我通过更多的输入扩展了文章中的代码.这样,就可以在编译时知道函数返回哪种类型的错误.
const ERR = Symbol('ERR');
type Err<ErrType extends string> = {
[ERR]: true;
message: string;
type: ErrType;
};
function isErr<ErrType extends string, Ok>(
x: Ok | Err<ErrType>,
): x is Err<ErrType> {
return typeof x === 'object' && x != null && ERR in x;
}
function Err<ErrType extends string>(
message: string,
type: ErrType,
): Err<ErrType> {
return { [ERR]: true, message: message, type: type };
}
您可以使用如下模式(link to playgound):
function errIfFalse(input: boolean) {
if (input) {
return Err("input is false", "falseInput")
}
return "sucess"
}
function doSomething() {
const a = errIfFalse(true)
if (isErr(a)) {
console.log("error: " + a.message)
return a.type
}
console.log(a)
return "no error"
}
const a = doSomething()
到目前为止,函数doSomething()
的返回类型被正确地推断为字符串文字"FalseInput"和"No Error"之一.但我对该模式有一个问题:当重构代码库时,以前返回错误的函数不再返回错误.包装函数可能会错误地推断其返回类型.下面的示例中就是这种情况.这可能会在代码库的其他部分造成令人困惑的错误.
function doSomething2() {
const a = true
if (isErr(a)) { // should throw compile time error because a is already narrowed down
// this code is unreachable but the compiler does not know that
console.log("error: " + a.message)
return a.type
}
console.log(a)
return "no error"
}
我想以某种方式修改类型缩小函数isErr()
,以便它只接受尚未缩小的输入.我怎样才能做到这一点呢?