如何根据事件名称缩小回调事件类型范围

How to narrow callback event type based on event name

提问人:manidos 提问时间:5/19/2021 最后编辑:Gajanan Kulkarnimanidos 更新时间:5/19/2021 访问量:547

问:

我正在尝试实现一个事件发射器。代码非常简单。

现在认为事件类型是 。 这就是问题所在,我想将类型缩小到正确的类型(取决于传递给函数)。tsceventHandler'ErrorEvent' | 'MessageEvent'tsceventNameon

能做到吗?

定义

interface Event {
  code: string;
}

interface ErrorEvent extends Event {
  xxx: number;
}

interface MessageEvent extends Event {
  yyy: number;
}

interface Events {
  error: ErrorEvent,
  message: MessageEvent
}

type EventHandler = (event: Events[keyof Events]) => void;

TS 代码

function on (eventName: keyof Events, eventHandler: EventHandler) {
  console.log(eventName)
}

on('message', (event) => { // ErrorEvent | MessageEvent
  console.log(event)
  console.log(event.code)
  console.log(event.xxx) //  Property 'xxx' does not exist on type 'ErrorEvent | MessageEvent'.
  console.log(event.yyy) //  Property 'yyy' does not exist on type 'ErrorEvent | MessageEvent'.
})
TypeScript 事件 回调

评论

1赞 Chund 5/19/2021
快速而肮脏的“与 ErrorEvent 一样未知的事件”,反之亦然,包装在 if 中。但在大多数情况下可能会很脏
1赞 captain-yossarian from Ukraine 5/19/2021
@manidos我相信这将是有帮助的 catchts.com/publish-subscribe

答:

4赞 aleksxor 5/19/2021 #1

首先,您必须摆脱 EventHandler 作为联合类型:

type EventHandler<K extends EventKeys> = (event: Events[K]) => void

这样,您就可以为每个混凝土的处理程序获得一个混凝土类型。 然后,确保函数的第二个参数类型依赖于第一个参数类型。因此,您必须在函数中引入一个类型参数才能将类型排在一行:Kon

function on <K extends EventKeys>(eventName: K, eventHandler: EventHandler<K>): void {}

我相信这应该做:

interface Event {
  code: string;
}

interface ErrorEvent extends Event {
  xxx: number;
}

interface MessageEvent extends Event {
  yyy: number;
}

interface Events {
  error: ErrorEvent,
  message: MessageEvent
}

type EventKeys = keyof Events
type EventHandler<K extends EventKeys> = (event: Events[K]) => void;

function on <K extends EventKeys>(eventName: K, eventHandler: EventHandler<K>): void {
  console.log(eventName)
}

on('message', (event) => {
  console.log(event)
  console.log(event.code)
  console.log(event.xxx) //  Property 'xxx' does not exist on type 'MessageEvent<any>'.
  console.log(event.yyy)
})

TS 游乐场