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

如何基于泛型类型设置方法参数为可选或必填

TypeScript 实现带泛型的 EventEmitter:指定泛型时 emit 参数必填,未指定时可选

需求说明

需要实现一个包含register和emit方法的EventEmitter类,通过泛型控制事件数据类型,支持两种使用场景:

  • 指定泛型类型:register的回调必须接收对应类型参数,emit必须传入该类型的值
  • 不指定泛型类型:register的回调无需参数,emit可直接调用无需传值

示例场景代码:

指定泛型类型的用法

const emitter1 = new EventEmitter<number>();
emitter1.register((value) => {
  console.log("Received:", value);
})();
emitter1.emit(43); // 必填参数,符合类型要求

未指定泛型类型的用法

const emitter2 = new EventEmitter();
emitter2.register(() => {
  console.log("Received (optional):");
})();
emitter2.emit(); // 无需传参,直接触发

解决方案

通过泛型默认值结合函数重载和条件类型实现需求:

class EventEmitter<T = undefined> {
  private handlers: ((value: T) => void)[] = [];

  // register 方法根据泛型类型自动适配回调参数
  register(handler: T extends undefined ? () => void : (value: T) => void) {
    this.handlers.push(handler as (value: T) => void);
    // 返回取消订阅的函数
    return () => {
      this.handlers = this.handlers.filter(h => h !== handler);
    };
  }

  // emit 方法重载:区分泛型指定/未指定的情况
  emit(value: T extends undefined ? never : T): void;
  emit(): void;
  emit(value?: T) {
    this.handlers.forEach(handler => handler(value as T));
  }
}

代码说明

  1. 泛型默认值:给泛型T设置默认值undefined,用户不指定泛型时,T自动取undefined
  2. register 方法:使用条件类型T extends undefined ? () => void : (value: T) => void,动态适配回调函数的参数要求
  3. emit 方法:通过函数重载实现类型约束:
    • 当T不是默认的undefined时,要求传入T类型的必填参数
    • 当T是undefined时,允许无参调用
    • 实际实现用可选参数value?: T兼容两种情况,类型层面通过重载保证约束生效

内容的提问来源于stack exchange,提问作者Henok Tesfaye

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:07:16