如何在TypeScript中基于动态事件注册表自动推断Handler参数类型?
动态注册事件的TypeScript自动类型推断方案
需求是开发TypeScript应用时,事件及其参数通过registerEvent动态注册,on方法要能自动根据注册信息推断参数类型,无需手动编写方法重载。
原实现的问题
原代码中Test类的泛型RE被定义为单一的ParameterSchema,无法存储多个不同事件的参数结构,导致on方法无法关联到具体事件的注册信息,类型推断失效。
解决方案
调整泛型设计,让Test类的泛型跟踪所有已注册的事件集合,利用TypeScript的条件类型和泛型推断实现自动类型关联:
type ParameterType<T> = { regexSnippet: string, parse?: (value: string) => any, type: T } const ParameterTypes = { "string": { regexSnippet: "\\w+" } as ParameterType<string>, "string?": { regexSnippet: "\\w*" } as ParameterType<string | undefined>, "number": { regexSnippet: "\\d+", parse: parseInt } as ParameterType<number>, "number?": { regexSnippet: "\\d*", parse: parseInt } as ParameterType<number | undefined>, } as const type ParameterTypesMap = typeof ParameterTypes type ParameterTypeKeys = keyof ParameterTypesMap type ParameterSchema = { [name: string]: ParameterTypeKeys } // 泛型改为跟踪所有已注册的事件集合 class Test<Events extends Record<string, ParameterSchema> = {}> { private registeredEvents: Events = {} as Events; // 扩展泛型,返回更新后的实例类型 registerEvent<EvName extends string, EvSchema extends ParameterSchema>( evname: EvName, args: EvSchema ): Test<Events & Record<EvName, EvSchema>> { (this.registeredEvents as any)[evname] = args; return this as Test<Events & Record<EvName, EvSchema>>; } // 基于泛型Events自动推断参数类型 on<EvName extends keyof Events>( evname: EvName, args: { [K in keyof Events[EvName]]: ParameterTypesMap[Events[EvName][K]]["type"] } ): void { // 业务逻辑实现 } } // 链式调用或分步调用,让TypeScript跟踪泛型变化 const test = new Test() .registerEvent("a", { name: "string", age: "number" }) .registerEvent("b", { nickname: "string?" }) .registerEvent("c", { count: "number" }); // 类型校验正常工作 test.on("c", { count: 12 }); // ✅ 正确 test.on("c", { zzzzz: 12 }); // ❌ 类型错误:不存在zzzzz属性 test.on("b", { nickname: "test" }); // ✅ 正确 test.on("b", { nickname: undefined }); // ✅ 正确 test.on("a", { name: "Alice", age: 30 }); // ✅ 正确 test.on("a", { name: "Alice", age: "30" }); // ❌ 类型错误:age应为number
关键说明
- 泛型跟踪事件集合:
Test类的泛型Events默认是空对象,每次调用registerEvent时,通过Events & Record<EvName, EvSchema>扩展泛型,记录新注册的事件及其参数结构。 registerEvent的返回类型:返回Test<Events & Record<EvName, EvSchema>>,让TypeScript能在链式调用时更新实例的泛型类型,分步调用时也能正确推断。on方法的类型推断:通过EvName extends keyof Events限定事件名,再用映射类型将事件的参数schema转换为实际的类型,实现与注册内容的强关联。
这样就完全满足约束条件:无需硬编码,on方法的类型校验完全与registerEvent的注册内容关联,动态生成类型校验规则。
内容的提问来源于stack exchange,提问作者Daniel de Andrade Varela
相关产品推荐
相关产品推荐

