You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为EventEmitter的eventPromise函数实现强类型返回值?

问题描述

我写了一个通用辅助函数eventPromise,用来通过await等待任意EventEmitter的事件触发,代码如下:

import { type EventEmitter } from 'eventemitter3'

/** 返回一个在指定事件触发时resolve的Promise */
export const eventPromise = async (emitter: EventEmitter, event: string) =>
  new Promise<any>(resolve => {
    emitter.once(event, d => resolve(d))
  })

我使用eventemitter3提供的强类型事件定义:

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

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

但尝试获取强类型返回值时出现错误:Property 'bar' does not exist on type 'unknown'。我试了下面的泛型写法,但返回类型还是unknown:

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>)
  })
}

我希望这个函数能通用适配任意EventEmitter,而不只是TestEvents,请问问题出在哪?

问题原因与修复方案

核心问题

你未正确导入eventemitter3提供的EventMap类型,且泛型约束写法存在问题,导致TypeScript无法正确推导事件参数类型。另外,不必要的类型断言也干扰了类型推导逻辑。

修复后的代码

import { type EventEmitter, type EventMap } from 'eventemitter3'

export const eventPromise = async <
  T extends EventMap,
  K extends keyof T
>(
  emitter: EventEmitter<T>,
  event: K
): Promise<Parameters<T[K]>[0] | undefined> => {
  return new Promise((resolve) => {
    emitter.once(event, (...args) => {
      // 取第一个参数作为Promise的resolve值,同时适配无参数事件场景
      resolve(args[0])
    })
  })
}

关键修改点

  • 显式导入EventMap:之前代码使用T extends EventMap但未导入该类型,TypeScript会将其识别为unknown,直接导致类型推导失败。
  • 简化泛型约束:用K extends keyof T替代EventEmitter.EventNames<T>,更贴合TypeScript原生类型推导逻辑,避免额外的类型解析歧义。
  • 兼容无参数事件:将返回类型设为Parameters<T[K]>[0] | undefined,避免事件无参数时出现类型报错。
  • 移除冗余类型断言:直接通过(...args)接收事件参数,无需强制转换监听函数类型,让TypeScript自动完成类型推导。

使用验证

const emitter = new TestEmitter()
// 现在可正确推导返回值类型为{ bar: string }
const data = await eventPromise(emitter, 'foo')
console.log(data.bar) // 不再出现类型错误

内容的提问来源于stack exchange,提问作者Herb Caudill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:52:46