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

TypeScript可辨识联合类型查找对象的正确类型定义方法

TypeScript 可辨识联合事件查找表类型报错解决方案

基础定义

首先明确基础事件类型与联合类型定义:

interface EventTypeBase {
  id: string;
  timestamp: string;
}

interface FizzChange extends EventTypeBase {
  name: 'fizz';
  payload: string;
}

interface BuzzChange extends EventTypeBase {
  name: 'buzz';
  payload: number;
}

// 所有事件的联合类型
type EventType = FizzChange | BuzzChange;

使用if语句做类型收窄时,TS可以正确推导分支内的类型,写法可正常运行:

const mapEventsWithIfs = (event: EventType) => {
  if (event.name === 'fizz') {
    return event.payload; // 自动推导为string类型
  }
  if (event.name === 'buzz') {
    return event.payload; // 自动推导为number类型
  }
  return;
}

报错原因

使用事件名查找对象绑定处理函数时,直接调用会触发类型错误,提示参数被推导为never:

// 报错示例
const mapEvents = (event: EventType) => {
  // 报错:Argument of type 'EventType' is not assignable to parameter of type 'never'
  return EventHandlersMap[event.name](event);
}

报错核心原因是:TS默认对索引取到的函数做类型合并时,会将所有处理函数的参数类型做交叉运算,要求传入的参数同时满足所有事件类型的约束。但FizzChange和BuzzChange的name属性是互斥的字面量类型,交叉结果为never,因此传入联合类型的event会触发类型错误。

正确实现方案

通过映射类型+泛型约束建立事件名与事件类型的绑定关系,即可让TS正确推导类型,无需任何不安全的类型断言:

  1. 首先定义严格类型约束的事件处理器映射表,通过映射类型自动关联每个事件名对应的事件类型:
const EventHandlersMap: {
  [K in EventType['name']]: (event: Extract<EventType, { name: K }>) => string | number | void
} = {
  fizz: (event) => event.payload, // event自动推导为FizzChange,payload为string类型
  buzz: (event) => event.payload, // event自动推导为BuzzChange,payload为number类型
}
  1. 将事件处理函数改为泛型函数,让TS自动关联传入事件的name类型与对应处理器的参数类型:
const mapEvents = <T extends EventType['name']>(event: Extract<EventType, { name: T }>) => {
  return EventHandlersMap[event.name](event);
}

该写法完全通过类型校验,同时保留完整的类型提示:

  • 编写处理器时可以自动推导对应事件的属性类型
  • 后续新增事件类型时,TS会强制要求映射表补充对应的处理函数,避免漏判
  • 调用mapEvents时传入任意EventType类型的事件,都可以正确推导返回值类型

如果不想封装泛型函数,也可以在调用时对event做临时类型断言,但该写法会丢失部分类型安全性,不推荐使用:

const mapEvents = (event: EventType) => {
  return EventHandlersMap[event.name](event as never);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:09:17