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

TypeScript中判别式联合与Map对象的类型定义问题

问题:判别式联合类型下Map对象的类型定义错误

现有一段使用判别式联合类型的可正常运行TypeScript代码:

type Alpha = { name: "alpha"; alpha: 1}
type Beta = { name: "beta"; beta: 2}
type Letters = Alpha | Beta

const calculateAlpha = (cfg: Alpha): number => {
    return cfg.alpha
}
const calculateBeta = (cfg: Beta): number => {
    return cfg.beta
}

const CalculatorFactory1 = (cfg: Letters) => {
  switch (cfg.name) {
    case "alpha":
      return () => calculateAlpha(cfg)
    case "beta":
      return () => calculateBeta(cfg)
    default:
      throw new Error()
  }
}

为提升可配置性,尝试将switch逻辑重构为Map对象,但定义letterMap类型时出现错误:

重构代码:

type LetterMap = Map<Letters["name"], (c: Letters) => number>
const letterMap: LetterMap = new Map([
    ["alpha", calculateAlpha],
    ["beta", calculateBeta]
])

const CalculatorFactory2 = (cfg: Letters) => {
    const func = letterMap.get(cfg.name)
    return func(cfg)        
}

错误信息:

Property 'alpha' is missing in type 'Beta' but required in type 'Alpha'.

解决方案:关联Map键与对应参数类型

问题根源

原LetterMap定义要求所有函数都能接收整个Letters联合类型作为参数,但calculateAlpha仅接受Alpha类型、calculateBeta仅接受Beta类型,类型约束不匹配导致报错。我们需要让Map的键与对应函数的参数类型一一绑定。

正确实现方式

方式1:使用映射类型明确键与类型的对应关系

先定义一个映射类型,将每个name值关联到对应的具体类型,再基于此定义Map的类型:

type Alpha = { name: "alpha"; alpha: 1}
type Beta = { name: "beta"; beta: 2}
type Letters = Alpha | Beta

// 定义name到对应类型的映射
type LetterTypeMap = {
  alpha: Alpha;
  beta: Beta;
};

const calculateAlpha = (cfg: Alpha): number => {
    return cfg.alpha
}
const calculateBeta = (cfg: Beta): number => {
    return cfg.beta
}

// 定义Map类型:键为LetterTypeMap的key,值为对应类型的处理函数
type LetterMap = Map<keyof LetterTypeMap, (c: Letters) => number>;

// 使用类型断言让TypeScript接受合法的键值对
const letterMap = new Map([
    ["alpha", calculateAlpha],
    ["beta", calculateBeta]
] as [keyof LetterTypeMap, (c: Letters) => number][]);

const CalculatorFactory2 = (cfg: Letters) => {
    const func = letterMap.get(cfg.name);
    if (!func) throw new Error("Invalid config type");
    return func(cfg);        
};

方式2:利用泛型函数实现类型安全调用

如果希望完全保留类型推断,可以用泛型约束让TypeScript自动匹配键与参数类型:

type Alpha = { name: "alpha"; alpha: 1}
type Beta = { name: "beta"; beta: 2}
type LetterTypeMap = {
  alpha: Alpha;
  beta: Beta;
};
type Letters = Alpha | Beta

const calculateAlpha = (cfg: Alpha): number => cfg.alpha;
const calculateBeta = (cfg: Beta): number => cfg.beta;

// 使用as const让TypeScript保留键值对的具体类型
const letterMap = new Map([
  ["alpha", calculateAlpha],
  ["beta", calculateBeta]
] as const);

// 泛型函数确保传入的cfg与获取的函数类型匹配
const CalculatorFactory2 = <K extends keyof LetterTypeMap>(cfg: LetterTypeMap[K]) => {
  const func = letterMap.get(K);
  if (!func) throw new Error("Invalid config type");
  return func(cfg);
};

说明

两种方式都解决了原类型定义的问题:

  • 方式1通过映射类型统一管理键与类型的对应关系,适合需要扩展更多类型的场景
  • 方式2利用泛型和as const实现更精确的类型推断,调用时无需额外类型断言

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:30:02