【问题标题】:How to strongly type an event emitter such that the handler's parameter type is inferred from the event type?如何强类型事件发射器,以便从事件类型推断处理程序的参数类型?
【发布时间】:2022-01-01 18:38:47
【问题描述】:

我正在尝试定义一个强类型的事件发射器,我最想要的是从传递给addEventHandler 函数的字符串中推断出回调的事件类型。

但到目前为止我失败了,我想出的是从回调中推断事件类型,而不是相反。

这是一个示例(带有fiddle):

interface NumberEvent {
  type: 'NumberEvent';
  num: number;
}

interface StringEvent {
  type: 'StringEvent';
  str: string;
}

type AnyEvent = NumberEvent | StringEvent;

const addEventHandler = <ET extends AnyEvent>(type: ET['type'], handler: ((event: ET) => void)) => {
  console.log(`added event handler for ${type}`);
}

addEventHandler('NumberEvent', (event: NumberEvent) => {
  // this is cool
});

addEventHandler('NumberEvent', (event: StringEvent) => {
  // this doesn't type check, good
});

addEventHandler('type does not exist', (x: any) => {
  // why no type error?
});

我不明白为什么最后一行要进行类型检查,因为没有 AnyEvent 类型为 'type does not exist' 的实例。

你能想出更好的方法来解决这个问题吗?

【问题讨论】:

  • 请参阅my article 它应该会有所帮助。相关问题herehere
  • 哦,但是!我之前已经开始阅读您的网站,stackoverflow 是多么的小世界啊!非常感谢,我的待办事项清单上有很多东西要读,但我最终会到达那里。

标签: typescript generics typing


【解决方案1】:

您可以通过使addEventHandler 通用事件类型而不是事件对象来实现此目的。

const addEventHandler = <ET extends AnyEvent['type']>(
  type: ET,
  handler: ((event: Extract<AnyEvent, { type: ET }>) => void)
) => {
  console.log(`added event handler for ${type}`);
}

您也可以使用AnyEvent &amp; { type: ET } 代替Extract&lt;AnyEvent &amp; { type: ET }

您的类型不能阻止最后一种情况的原因是因为ET 被推断为anyany["type"] 仍然是 any,所以它允许任何字符串。

以上版本仍然不会阻止某人这样做:

addEventHandler<any>('type does not exist', (x: any) => {
  // explicitly providing <any>
});

您可以通过使用&lt;anything&gt; &amp; anyany 的事实来防止这种情况,但我个人不会打扰。除非故意尝试破坏您的类型,否则没有人可能会在此处提供any。使用any 检查,您还可以返回到您的通用:

type NotAny<T> = 0 extends (1 & T) ? never : T; 

const addEventHandler = <ET extends AnyEvent>(type: NotAny<ET["type"]>, handler: ((event: ET) => void)) => {
  console.log(`added event handler for ${type}`);
}

【讨论】:

  • 太棒了!非常感谢您的解决方案和解释。我曾尝试过类似的东西,但我一定搞砸了,我不知道如何执行这种“提取”,现在我知道了。是的,如果有人决定明确通过任何...好吧,此时我无能为力,这是他们的问题。
猜你喜欢
  • 1970-01-01
  • 2023-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-02
  • 2021-12-30
  • 1970-01-01
相关资源
最近更新 更多