我试图实现一个自定义的Error类,该类将根据错误代码接受不同种类的数据。我非常确定我想做的事情太复杂,无法推断出打字稿,但是令我惊讶的是,这行得通:
const enum ERROR_CODES {
E_AUTHORIZATION = 'Authorization error',
E_REQUEST = 'Request failed',
E_INVALID = 'Invalid data',
}
interface ERROR_TYPES {
[ERROR_CODES.E_AUTHORIZATION]: string
[ERROR_CODES.E_REQUEST]: { url: string; status: number }
[ERROR_CODES.E_INVALID]: { action: string; field: string }
}
class MyError<TError extends ERROR_CODES> extends Error {
constructor(
public readonly code: TError,
public readonly data: ERROR_TYPES[TError],
) { super(code) }
}
现在我可以这样使用它:
throw new MyError(ERROR_CODES.E_AUTHORIZATION, 'whatever')
throw new MyError(ERROR_CODES.E_AUTHORIZATION, {
operation: 'login',
field: 'email',
})
这很好。我想做的另一件事是创建不需要数据的错误代码。由于可以定义这样的功能:
function foo(bar: void) {}
foo()
我的下一个逻辑步骤是编写此代码:
const enum ERROR_CODES {
// ...
E_UNKNOWN = 'Unknown error'
}
interface ERROR_TYPES {
// ...
[ERROR_CODES.E_UNKNOWN]: void
}
现在打字稿的表现很奇怪。如果我这样写:
throw new MyError(ERROR_CODES.E_UNKNOWN, undefined)
有效。如果我这样写:
throw new MyError(ERROR_CODES.E_UNKNOWN)
说Expected 2 arguments, but got 1.
。如果我写这样的话:
throw new MyError(ERROR_CODES.E_UNKNOWN, void 0)
,它应该与第一个示例基本相同,然后显示Expected 'undefined' and instead saw 'void'.
。这里发生了什么,有可能仅用一个参数就使第二个示例起作用?
答案 0 :(得分:1)
我无法复制“预期的undefined
,而是看到了void
”。
这就是我可能会采用的方法。为了“可选地使函数参数可选”,我将参数列表表示为rest tuple。考虑以下类型别名:
type UndefParamToOptional<T> = undefined extends T ? [T?] : [T];
类型UndefParamToOptional<string>
仅是[string]
,而UndeParamToOptional<string | undefined>
是[string?]
。这是一个具有一个optional element的元组,对应一个可选的函数参数。然后我们可以像这样实现MyError
:
class MyError<TError extends ERROR_CODES> extends Error {
constructor(
code: TError,
...[data]: UndefParamToOptional<ERROR_TYPES[TError]>
);
constructor(public readonly code: TError, public readonly data: ERROR_TYPES[TError]) {
super(code);
this.data = data;
}
}
我正在使用单个overload签名来显示您打算如何调用它,同时保持实现签名不变。
现在,这应该符合您的预期:
throw new MyError(ERROR_CODES.E_UNKNOWN); // okay
希望有帮助。祝你好运!