Typescript条件空参数类型

时间:2019-11-03 15:17:10

标签: typescript types

我试图实现一个自定义的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'.。这里发生了什么,有可能仅用一个参数就使第二个示例起作用?

1 个答案:

答案 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

希望有帮助。祝你好运!

Link to code