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

TypeScript中匹配字符串与对象联合类型并保留值的实现

实现带关联值枚举的类型安全匹配函数

针对从Rust枚举转换而来的TypeScript类型(字符串或单键对象的联合),我们可以通过分布式条件类型和联合函数类型实现类型安全的matchEnum函数,让回调参数的类型自动匹配对应枚举项的关联值。

步骤1:定义类型工具

先通过辅助类型拆解枚举结构,提取键和对应的关联值:

// 提取枚举类型的所有可能键
type EnumKeys<E> = 
  E extends string ? E : 
  E extends { [K in infer Key]: unknown } ? Key : 
  never;

// 根据键获取对应的关联值类型,无关联值时为undefined
type EnumValueForKey<E, K extends EnumKeys<E>> = 
  E extends { [_ in K]: infer V } ? V : 
  undefined;

// 生成匹配回调的联合函数类型,每个键对应一个准确的签名
type EnumMatcher<E, RT> = {
  [K in EnumKeys<E>]: (key: K, value: EnumValueForKey<E, K>) => RT;
}[EnumKeys<E>];

步骤2:实现matchEnum函数

基于上述类型工具编写函数逻辑:

export function matchEnum<E, RT>(enm: E, matcher: EnumMatcher<E, RT>): RT {
  if (typeof enm === 'string') {
    // 处理无关联值的字符串枚举项
    return matcher(enm as EnumKeys<E>, undefined as EnumValueForKey<E, typeof enm>);
  } else {
    // 处理带关联值的单键对象枚举项
    const [key] = Object.keys(enm) as [EnumKeys<E>];
    return matcher(key, enm[key] as EnumValueForKey<E, typeof key>);
  }
}

用法示例

用你提供的枚举类型测试:

type StructT = { num: number };
type EnumWithValues = (
  { "TupleVal": [number, number] } |
  { "StructVal": StructT } |
  "SimpleVal"
);

// 无关联值的情况
const simpleVal: EnumWithValues = "SimpleVal";
matchEnum(simpleVal, (key, args) => {
  // key类型:"SimpleVal",args类型:undefined
  console.log(`类型:${key},无关联值`);
});

// 元组关联值的情况
const tupleVal: EnumWithValues = { TupleVal: [10, 20] };
matchEnum(tupleVal, (key, args) => {
  // key类型:"TupleVal",args类型:[number, number]
  console.log(`类型:${key},第一个值:${args[0]}`);
});

// 结构体关联值的情况
const structVal: EnumWithValues = { StructVal: { num: 30 } };
matchEnum(structVal, (key, args) => {
  // key类型:"StructVal",args类型:StructT
  console.log(`类型:${key},num值:${args.num}`);
});

这个实现会让TypeScript自动推断每个枚举项对应的参数类型,避免了之前版本中args始终是联合类型的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:16:00