遍历配置对象时TypeScript无法正确推断函数参数类型
问题:TypeScript遍历事件配置时无法推断对应事件类型
我有一组包含eventName的配置对象,eventName对应应用中可触发的事件名称,事件触发时监听器会收到对应类型的event对象。
示例代码:
type EventHandler<E> = (event: E) => void; // 事件名到对应类型处理器的映射 type EventMap = { onStart: EventHandler<StartEvent>; onEnd: EventHandler<EndEvent>; }; const configs = [ buildConfig('onStart'), buildConfig('onEnd') ];
我需要遍历该配置列表,生成另一组包含handlerFactory属性的配置对象,handlerFactory是一个为事件构建对应处理器的函数,用于通过闭包提供额外上下文。
相关类型定义:
type AdditionalContext = unknown; // 示例中实际类型不重要 type HandlerConfig<E extends keyof EventMap = keyof EventMap> = { eventName: E; handlerFactory: (context: AdditionalContext) => EventMap[E]; };
问题在于,在.map回调中TypeScript无法正确推断事件类型:
const handlerConfigs: HandlerConfig[] = configs.map(({ eventName }) => { return { eventName, handlerFactory: (context) => { // FIXME: 为什么e是any类型?它应该是对应eventName处理器的事件类型。 return (e) => { console.log('Did something cool!', context); }; } }; });
解决方案
这个功能完全可行,问题出在TypeScript的类型推断限制:当你在泛型数组的map回调中动态返回不同泛型参数的HandlerConfig时,TypeScript无法自动为每个eventName关联对应的事件类型。可以通过以下方式解决:
步骤1:约束原数组的类型精度
先确保configs的类型被精确推断,避免TypeScript把它处理为联合类型数组:
const configs = [ buildConfig('onStart'), buildConfig('onEnd') ] as const; // 添加as const保留每个元素的具体eventName类型
步骤2:给map回调添加泛型约束
通过泛型参数明确当前迭代项的eventName是EventMap的具体键,让TypeScript关联对应事件类型:
const handlerConfigs = configs.map(<E extends keyof EventMap>({ eventName }: { eventName: E }) => { return { eventName, handlerFactory: (context: AdditionalContext): EventMap[E] => { return (e) => { // 此时e会被正确推断为对应事件类型 console.log('Did something cool!', context); // 可安全使用e的类型属性,比如e.startTime(若为StartEvent) }; } }; }) as HandlerConfig[];
额外:确保buildConfig的类型正确
如果buildConfig本身没有返回带具体eventName类型的对象,需要先修正它的类型定义:
function buildConfig<E extends keyof EventMap>(eventName: E) { return { eventName }; }
完成上述修改后,e会被正确推断为对应eventName的事件类型,不再是any。
内容的提问来源于stack exchange,提问作者Logan Price
相关产品推荐
相关产品推荐

