TypeScript泛型默认参数优化:实现无参空事件调用
解决TypeScript事件构造函数的无参数调用需求
你可以通过条件类型约束函数签名或者函数重载实现这个需求,让默认泛型(null)对应的事件构造函数支持无参数调用,同时保留带数据事件的类型校验。
方案一:条件类型约束函数返回值
通过条件类型判断泛型D是否为null,动态生成对应的函数签名:
export function defineEvent<D extends Record<string, any> | null = null>(name: string) { // 根据泛型D的类型,定义返回函数的类型 type EventFn = D extends null ? () => null : (data: D) => D; const result = ((data?: D) => { // 无参数时返回null,有参数时返回传入的数据 return data ?? null; }) as EventFn; result.$event = name; return result; }
用法示例
- 无数据事件(默认泛型):无需传参直接调用
const emptyEvent = defineEvent("testEvent"); emptyEvent(); // ✅ 正常调用,返回null
- 带数据事件:保持原有类型校验和调用方式
const testEvent = defineEvent<{ name: string }>("testEvent"); testEvent({ name: "Bob" }); // ✅ 正常调用,返回传入的对象
方案二:函数重载
通过定义多个函数重载签名,明确区分无数据和带数据的事件构造函数:
// 重载签名1:无数据事件(默认场景) export function defineEvent(name: string): () => null; // 重载签名2:带数据事件(指定泛型) export function defineEvent<D extends Record<string, any>>(name: string): (data: D) => D; // 通用实现函数 export function defineEvent<D extends Record<string, any> | null = null>(name: string) { function result(data?: D) { return data ?? null; } result.$event = name; return result; }
用法示例
和方案一完全一致,TypeScript会根据调用场景自动匹配对应的重载签名:
// 无数据事件 const emptyEvent = defineEvent("testEvent"); emptyEvent(); // ✅ 正常调用 // 带数据事件 const testEvent = defineEvent<{ age: number }>("ageEvent"); testEvent({ age: 25 }); // ✅ 正常调用
两种方案都能满足你的需求,方案一更依赖类型系统的条件判断,方案二更直观地通过重载区分不同场景,可根据个人习惯选择。
内容的提问来源于stack exchange,提问作者JoeBayLD
相关产品推荐
相关产品推荐

