You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript如何为多可辨识联合的事件处理函数数组定义类型

问题原因

  1. TypeScript 中函数参数是逆变的:对于 EventHandler<T> 这种函数类型,T 处在参数位置,所以如果 A 是 B 的子类型,那么 EventHandler<B> 才是 EventHandler<A> 的子类型,反过来不成立。你手动给泛型传 EventTypes 时,要求所有handler都能接受任意EventTypes类型的事件,而你写的handler1只能处理FIRST类型的事件,自然类型不匹配。
  2. 你原来的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 04:18:04