TypeScript中如何为枚举事件绑定对应类型的处理函数签名
实现方案
你可以通过泛型+事件签名映射的方式实现需求,不需要额外声明运行时变量,所有关联逻辑仅在类型层面生效,无额外运行时开销。
方案1:泛型映射类型(更易维护,推荐)
步骤1:定义事件与处理函数的映射关系
首先声明一个接口,将每个枚举值对应的处理函数签名一一关联,这一步是纯类型定义,不会生成任何运行时代码,也不需要额外赋值:
enum Event { EventOne, EventTwo } // 事件与处理函数的签名映射,仅用于类型校验 interface EventHandlerMap { [Event.EventOne]: (foo: number, bar: string) => void [Event.EventTwo]: (foo: string) => void }
步骤2:改造registerEvent为泛型函数
给函数添加约束为Event枚举的泛型参数,将第二个入参的类型绑定为映射中对应泛型的签名:
function registerEvent<T extends Event>(event: T, handler: EventHandlerMap[T]) { // 此处保留你原有的事件注册逻辑即可 }
效果验证
调用时TS会自动根据传入的事件枚举值推断对应处理函数的签名,支持智能提示,类型不匹配会直接报错:
// 正常匹配:EventOne对应的处理函数参数自动推断为number、string registerEvent(Event.EventOne, (foo, bar) => { console.log(foo.toFixed(2), bar.length) // 参数属性有智能提示 }) // 正常匹配:EventTwo对应的处理函数参数自动推断为string registerEvent(Event.EventTwo, (foo) => { console.log(foo.length) }) // 类型报错:EventOne的处理函数第二个参数应为string,此处声明为boolean不符合要求 registerEvent(Event.EventOne, (foo: number, bar: boolean) => {})
后续新增事件只需要在Event枚举加值,同时在EventHandlerMap中补充对应签名即可,不需要修改registerEvent的代码,维护成本极低。
方案2:函数重载(适合事件数量少的场景)
如果事件数量很少,也可以直接通过函数重载实现,不需要额外定义映射接口:
enum Event { EventOne, EventTwo } // 重载签名:逐个声明每个事件对应的处理函数类型 function registerEvent(event: Event.EventOne, handler: (foo: number, bar: string) => void): void function registerEvent(event: Event.EventTwo, handler: (foo: string) => void): void // 实现签名:仅对内生效,对外不会暴露 function registerEvent(event: Event, handler: (...args: any[]) => void) { // 原有事件注册逻辑 }
效果和方案1完全一致,缺点是新增事件时需要额外加重载签名,事件多了之后会比较冗余。
内容的提问来源于stack exchange,提问作者Blade
相关产品推荐
相关产品推荐

