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

TypeScript可扩展EmitterMap接口库内类型推断报错问题求助

问题分析与解决方案

问题根源在于你定义的EmitterMap是空接口时,keyof EmitterMap等于never,导致泛型T的约束变成never | never[],此时T[number]的类型也是never,用never去索引EmitterMap就会触发TypeScript的类型错误。

解决这个问题的核心是调整类型推断逻辑,确保在EmitterMap为空时(库编译阶段)类型合法,同时在用户扩展接口后能正确推断数据类型。

修复后的库内代码

// 库内的空接口定义保持不变
interface EmitterMap {}

// 定义辅助类型处理事件对应的数据类型
type EventDataType<T> = 
  // 单个事件名:直接取对应类型
  T extends keyof EmitterMap ? EmitterMap[T] :
  // 事件名数组:取数组元素对应的类型联合
  T extends readonly (infer EventKey)[] ? EventKey extends keyof EmitterMap ? EmitterMap[EventKey] : never :
  // 其他非法情况返回never
  never;

// 重写sender函数
function sender<const T extends keyof EmitterMap | readonly (keyof EmitterMap)[]>(
  event_names: T,
  data: EventDataType<T>
) {
  // 函数业务逻辑
}

修复逻辑说明

  1. 避免直接索引never类型:通过辅助类型EventDataType的条件分支,先区分单个事件和事件数组的场景,绕开了直接用T[number]索引空接口的问题。
  2. 兼容const泛型推断:使用readonly (infer EventKey)[]替代普通数组类型,既支持用户传入的数组字面量,也符合TypeScript对const泛型的推断规则。
  3. 自动适配用户扩展:当用户通过declare module扩展EmitterMap后,keyof EmitterMap会自动变为用户定义的键集合,T的约束和EventDataType的推断逻辑会同步生效。

用户扩展后的使用示例

用户扩展接口后:

declare module "my-module" {
  interface EmitterMap {
    abc: string;
    def: number;
  }
}

// 单个事件:data类型自动推断为string
sender("abc", "hello world");

// 事件数组:data类型自动推断为string | number
sender(["abc", "def"], 123);

内容的提问来源于stack exchange,提问作者Autumn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:37:26