这个函数的返回值可以强类型化吗?

问题描述 投票:0回答:1

我有一个辅助函数,可以让我在

await
上处理
EventEmitter
事件。

import { type EventEmitter } from 'eventemitter3'

/** Returns a promise that resolves when the given event fires */
export const eventPromise = async (emitter: EventEmitter, event: string) =>
  new Promise<any>(resolve => {
    emitter.once(event, d => resolve(d))
  })

所以我可以等待下一个

foo
活动如下:

await eventPromise(someEmitter, 'foo')

到目前为止,效果很好。

我正在使用 eventemitter3,它为我提供了强类型事件:

type TestEvents = {
  foo: (payload: { bar: string }) => void
}

class TestEmitter extends EventEmitter<TestEvents> {
  test() {
    this.emit('foo', { bar: 'pizza' })
  }
}

所以看起来

eventPromise
的返回值应该可以是强类型的:

const testEmitter = new TestEmitter()
const { bar } = await eventPromise(testEmitter, 'foo') 

但这给了我一个错误,

Property 'bar' does not exist on type 'unknown'
。 (参见这个游乐场。)

我绕了很多圈子,试图让

eventPromise
返回强类型值。这是我得到的最接近的:

export const eventPromise = async <
  T extends EventMap,
  K extends EventEmitter.EventNames<T> = EventEmitter.EventNames<T>,
>(
  emitter: EventEmitter<T>,
  event: K
) => {
  return new Promise<Parameters<T[K]>[0]>(resolve => {
    const listener = (payload: Parameters<T[K]>[0]) => resolve(payload)
    emitter.once(event, listener as EventEmitter.EventListener<T, K>)
  })
}

可以编译,但返回类型仍然是

unknown
。 (参见这个游乐场。)

老实说,我觉得这些体操都没有必要——原始函数不应该有足够的信息让 TypeScript 推断其返回类型吗?

我错过了什么?

typescript typescript-generics eventemitter
1个回答
0
投票

我能够使用下面的代码使其工作。

为了方便,我提取了更多

TestMessages
的定义,与您所显示的代码的相关差异在
eventPromise
,即:

  • 我实际上是从promise回调返回;
  • 我已经为返回的 Promise 指定了类型。

eventPromise
可以进一步抽象,以便在输入中获取具有任意事件的发射器,因此它应该成为 generic,但是否需要这取决于具体要求。

import { EventEmitter } from 'eventemitter3'

type TestMessages = {
    foo: { bar: string }
}

type TestEvents = {
    foo: (payload: TestMessages["foo"]) => void
}

class TestEmitter extends EventEmitter<TestEvents> {
    test() {
        this.emit('foo', { bar: 'pizza' })
    }
}

/** Returns a promise that resolves when the given event fires */
export const eventPromise = async (emitter: TestEmitter, event: keyof TestEvents) =>
    new Promise<TestMessages[typeof event]>(resolve => {
        return emitter.once(event, d => resolve(d))
    });

const testEmitter = new TestEmitter();

const { bar } = await eventPromise(testEmitter, 'foo');

游乐场链接

© www.soinside.com 2019 - 2024. All rights reserved.