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

TypeScript中基于枚举类型实现函数参数类型推断与补全

TypeScript根据第一个参数类型推断第二个参数的实现方案

问题描述

我在开发TypeScript项目时遇到需求:希望函数的第二个参数data能根据第一个参数type实现类型推断与自动补全。

给定类型定义:

enum MessageType {
  FOO = "FOO",
  BAR = "BAR",
  BAZ = "BAZ",
}

interface DataFoo {
  type: MessageType.FOO
  payload: string
}

interface DataBarOrBaz {
  type: MessageType.BAR | MessageType.BAZ
  name: string
  age: number
}

type Data = DataFoo | DataBarOrBaz

需要开发的函数结构如下,需为data参数提供自动补全:

function emit<T extends MessageType>(type: T, data: ???) {}

预期效果:传入不同MessageType枚举值时,data自动匹配对应类型并补全字段。但使用Extract工具类型尝试时,针对type为枚举联合类型的接口无法生效——传入BAR/BAZ时data类型变为Omit<never, "type">。请问TypeScript 5.x版本中如何实现该需求?

解决方案

问题核心是Extract<Data, { type: T }>无法正确匹配type字段为联合类型的成员(如DataBarOrBaz),因为Extract会进行严格的字面量类型匹配。以下两种方案可在TypeScript 5.x中解决该问题:

方案一:利用条件类型分布式特性

通过条件类型遍历Data联合类型,筛选出type包含当前T的成员:

type DataForType<T extends MessageType> = 
  Extract<Data, { type: T }> extends never 
    ? Extract<Data, { type: infer U }> extends { type: T | infer _ } 
      ? Extract<Data, { type: U }> 
      : never
    : Extract<Data, { type: T }>;

function emit<T extends MessageType>(type: T, data: Omit<DataForType<T>, 'type'>) {}

方案二:构建类型映射表(可读性更强)

手动创建MessageType到对应数据类型的映射表,通过索引访问直接获取对应类型:

type DataMap = {
  [MessageType.FOO]: Omit<DataFoo, 'type'>;
  [MessageType.BAR]: Omit<DataBarOrBaz, 'type'>;
  [MessageType.BAZ]: Omit<DataBarOrBaz, 'type'>;
};

function emit<T extends MessageType>(type: T, data: DataMap[T]) {}

效果验证

两种方案均能实现预期功能:

  • 传入MessageType.FOO时,data自动补全为{ payload: string }
  • 传入MessageType.BAR或MessageType.BAZ时,data自动补全为{ name: string; age: number }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:06:02