简体   繁体   English

Typescript 条件无效参数类型

[英]Typescript conditional void parameter type

I was trying to implement a custom Error class, which would accept different kinds of data depending on the error code.我试图实现一个自定义错误 class,它将根据错误代码接受不同类型的数据。 I was pretty sure that was I wanted to do was too complex for typescript to infer, but, to my surprise, this worked:我很确定我想做的事情太复杂了,以至于 typescript 无法推断,但令我惊讶的是,这行得通:

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) }
}

Now I can use it like this:现在我可以像这样使用它:

throw new MyError(ERROR_CODES.E_AUTHORIZATION, 'whatever')
throw new MyError(ERROR_CODES.E_AUTHORIZATION, { 
  operation: 'login',
  field: 'email',
})

This works fine.这工作正常。 Another thing I wanted to do is to create such error codes that need no data.我想做的另一件事是创建不需要数据的错误代码。 Since it is possible to define functions like this:因为可以定义这样的函数:

function foo(bar: void) {}
foo()

My next logical step was to write this:我的下一个合乎逻辑的步骤是写这个:

const enum ERROR_CODES {
  // ...
  E_UNKNOWN = 'Unknown error'
}
interface ERROR_TYPES {
  // ...
  [ERROR_CODES.E_UNKNOWN]: void
}

Now typescript behaves in quite a strange way.现在 typescript 表现得非常奇怪。 If I write this:如果我写这个:

throw new MyError(ERROR_CODES.E_UNKNOWN, undefined)

it works.有用。 If I write this:如果我写这个:

throw new MyError(ERROR_CODES.E_UNKNOWN)

it says Expected 2 arguments, but got 1. .它说Expected 2 arguments, but got 1. . If I write something like this:如果我写这样的东西:

throw new MyError(ERROR_CODES.E_UNKNOWN, void 0)

which should basically be the same as the first example, then it says Expected 'undefined' and instead saw 'void'.这应该与第一个示例基本相同,然后它说Expected 'undefined' and instead saw 'void'. . . What is happening here and is it possible to make the second example work with just one argument?这里发生了什么,是否可以使第二个示例仅使用一个参数?

I can't reproduce "expected undefined but instead saw void ".我无法重现“预期undefined但看到void ”。


Here's how I might approach what you're trying to do.以下是我可能会如何处理您正在尝试做的事情。 To "optionally make a function parameter optional", I'd represent the parameter list as as rest tuple .为了“可选地使 function 参数可选”,我将参数列表表示为rest tuple Consider this type alias:考虑这种类型别名:

type UndefParamToOptional<T> = undefined extends T ? [T?] : [T];

The type UndefParamToOptional<string> is just [string] , but UndeParamToOptional<string | undefined> UndefParamToOptional<string>类型只是[string] ,但UndeParamToOptional<string | undefined> UndeParamToOptional<string | undefined> is [string?] . UndeParamToOptional<string | undefined>[string?] That's a tuple with a single optional element corresponding to an optional function parameter.这是一个具有单个可选元素的元组,对应于可选的 function 参数。 Then we can implement MyError like this:然后我们可以像这样实现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;
  }
}

I'm using a single overload signature to show how you intend to call it, while leaving the implementation signature unchanged.我使用单个重载签名来显示您打算如何调用它,同时保持实现签名不变。

Now this should behave as you expect:现在这应该如您所愿:

throw new MyError(ERROR_CODES.E_UNKNOWN); // okay

Hope that helps.希望有帮助。 Good luck!祝你好运!

Link to code 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM