TypeScript如何为多可辨识联合的事件处理函数数组定义类型
问题原因
- TypeScript 中函数参数是逆变的:对于
EventHandler<T>这种函数类型,T处在参数位置,所以如果A是B的子类型,那么EventHandler<B>才是EventHandler<A>的子类型,反过来不成立。你手动给泛型传EventTypes时,要求所有handler都能接受任意EventTypes类型的事件,而你写的handler1只能处理FIRST类型的事件,自然类型不匹配。 - 你原来的
someFunctionAcceptsHandlers泛型定义要求数组里所有handler都接收同一个TEvent类型,所以第一个handler的类型会直接锁定泛型为FIRST事件类型,第二个handler自然不符合要求。
解决方案
方案1:定义事件联合对应的handler联合类型
先写一个工具类型,把你的可辨识联合事件类型,自动映射为所有对应单事件handler的联合:
type EventHandlerUnion<TEvent extends {type: string}> = TEvent extends any ? EventHandler<TEvent> : never // 针对你的EventTypes,这个类型等价于: // EventHandler<{type: "FIRST", someProp: string}> | EventHandler<{type: "SECOND", otherProp: string}>
然后修改someFunctionAcceptsHandlers的参数类型:
function someFunctionAcceptsHandlers<TEvent extends { type: string; [key: string]: any }>( handlers: EventHandlerUnion<TEvent>[] ) { // 原有逻辑不变 }
调用的时候手动指定泛型为EventTypes即可:
someFunctionAcceptsHandlers<EventTypes>([handler1, handler2]) // 无报错,类型检查正常
方案2:自动推导元组类型(无需手动传泛型)
如果你不想每次调用都手动传泛型,可以修改函数定义,让它自动推导传入的handler数组的每个元素类型:
type AllowedHandlers<TEvent extends {type: string}> = EventHandlerUnion<TEvent> function someFunctionAcceptsHandlers<T extends AllowedHandlers<EventTypes>[]>(handlers: [...T]) { // 原有逻辑不变 } // 调用时不需要手动传泛型,自动推导 someFunctionAcceptsHandlers([handler1, handler2]) // 类型正常,无报错
两种方案都能保留每个handler内部的类型窄化能力,你依然可以在handler1里正常访问someProp,handler2里正常访问otherProp,不会丢失类型安全。
内容的提问来源于stack exchange,提问作者Highmastdon
相关产品推荐
相关产品推荐

