如何基于泛型类型设置方法参数为可选或必填
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)); } }
代码说明
- 泛型默认值:给泛型
T设置默认值undefined,用户不指定泛型时,T自动取undefined - register 方法:使用条件类型
T extends undefined ? () => void : (value: T) => void,动态适配回调函数的参数要求 - emit 方法:通过函数重载实现类型约束:
- 当
T不是默认的undefined时,要求传入T类型的必填参数 - 当
T是undefined时,允许无参调用 - 实际实现用可选参数
value?: T兼容两种情况,类型层面通过重载保证约束生效
- 当
内容的提问来源于stack exchange,提问作者Henok Tesfaye
相关产品推荐
相关产品推荐

