事件源命名的事件使用TypeScript

9

我正在尝试在Typescript中使用EventSource,但是当使用命名事件时无法正确地为响应类型进行定义。

我尝试过:

const evtSource = new EventSource('/my-url');

const parseMyEvent = (evt: Event) => {
  const data: MyDataInterface = JSON.parse(evt.data);
  console.log(data)
}

evtSource.addEventListener('my-event', parseMyEvent);

失败了,因为 Event 没有 data 属性。

const evtSource = new EventSource('/my-url');

const parseMyEvent = (evt: MessageEvent) => {
  const data: MyDataInterface = JSON.parse(evt.data);
  console.log(data)
}

evtSource.addEventListener('my-event', parseMyEvent);

出现错误信息"No overload matches this call.",在evtSource.addEventListener('my-event', parseMyEvent)处失败。

我知道MessageEvent是一个泛型接口,但我应该使用什么作为它的类型?

我正在使用TS 3.5.3,所以我尝试安装外部类型@types/eventsource,但没有成功(我知道这是用于polyfill EventSource库,但我还是试了)。

当使用泛型evtSource.onMessage = fn时,它可以正常工作而没有任何问题。

应该可以在TS中对EventSource事件的监听器/响应进行类型化,但是如何做呢?


1
看起来EventSource.addEventListener有一个泛型:addEventListener <K extends keyof EventSourceEventMap>(type: K, ....但它只接受 "error" | "message" | "open",所以并没有太多帮助。 - Linda Paiste
2个回答

7
以下代码应该有效。基本上,您正在使用TypeScript的类型断言,并让编译器相信底层事件实际上是MessageEvent类型的对象:
const evtSource = new EventSource('/my-url');

const parseMyEvent = (evt: Event) => {
  const messageEvent = (evt as MessageEvent);  // <== This line is Important!!
  const data: MyDataInterface = JSON.parse(messageEvent.data);
  console.log(data)
}

evtSource.addEventListener('my-event', parseMyEvent);


3
EventSource上的addEventListener方法有一个通用类型,它指向一种类型映射接口(EventSourceEventMap)。 正如评论中提到的那样,该通用类型最初仅接受"error" | "message" | "open",但这是因为这些是默认映射中唯一定义的类型。 它的意图是您可以添加自己的类型来扩展自定义事件的地图。因此,在您的情况下,您需要做的是:
declare global {
  interface EventSourceEventMap {
    ['my-event']: MessageEvent<MyDataInterface>;
  }
}

因此,TypeScript 不仅知道传递给 my-event 的消息确实有一个 data 属性,它也知道该属性的类型。


2
这对我有用,除了上面代码中的MyDataInterface应该始终为string。MessageEvent接口用于比SSE更通用的用途。在SSE的特定上下文中,数据属性始终为字符串,其中可能包含序列化对象。 - Trygve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接