OpenTok 事件 Typescript 键入

OpenTok event Typescript typing

我正在尝试通过 OpenTok API 使用 'signal' 事件实现聊天 publish/subscribe。

这是我的有效事件侦听器(收到信号):

// Listen for signal CHAT_MESSAGE
sess.on('signal:CHAT_MESSAGE', event => {
 
  const message = event.data

  ...

}) 

问题是 typescript 无法将 event.data 识别为有效的 属性。类型来自Session class:

Session.signal: Event<'signal', Session> & {
    type?: string;
    data?: string;
    from: Connection;
};

我试过从 Session class 中选择类型

const message = event.data as Session['signal']

Typescript 抱怨 Property 'data' does not exist on type 'Event<string, any>'. 我怀疑是因为 TS 没有正确识别事件类型...

然后我首先尝试转换为 'unknown':

const signal = (event as unknown) as Session['signal']
const msg = signal.data

现在TS抱怨:Property 'data' does not exist on type '(signal: { type?: string | undefined; data?: string | undefined; to?: Connection | undefined; }, callback: (error?: OTError | undefined) => void) => void'.ts(2339)

我不确定为什么它不认为 data 是道具,而同时它似乎又说它是...

如何解决这个问题,最好不要禁用 TS 类型检查?

问题是Session['signal']是一个函数:

signal(
    signal: { type?: string, data?: string, to?: Connection },
    callback: (error?: OTError) => void
): void;

您可能需要的类型来自 Session 的 class 祖先 OTEventEmitter:

export class Session extends OTEventEmitter<{
    ...
    signal: Event<'signal', Session> & {
      type?: string;
      data?: string;
      from: Connection;
    };
    ...

OTEventEmitter.on 方法类型:

class OTEventEmitter<EventMap> {
    on<EventName extends keyof EventMap>(
        eventName: EventName,
        callback: (event: EventMap[EventName]) => void,
        context?: object
    ): void;

    on(
        eventName: string,
        callback: (event: Event<string, any>) => void,
        context?: object
    ): void;
    ...

您可能会注意到,当 Session 扩展 OTEventEmitter 时,EventMap 中没有 signal:CHAT_MESSAGE。只有 signal.

因此,如果您希望 signal:CHAT_MESSAGE 被视为 signal 事件,您应该将其写为:

sess.on('signal:CHAT_MESSAGE' as 'signal', event => {
    const message = event.data // no error
    // `event` has type
    // Event<'signal', Session> & {
    //     type?: string;
    //     data?: string;
    //     from: Connection;
    // }
    ...

此类型转换没有运行时人工制品。唯一的目的是确保您的 signal:CHAT_MESSAGE 事件与 signal 的事件具有相同的结构。虽然与往常一样使用 as 关键字,但现在您有责任确保它是真实的。