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

为何TypeScript在推断与模板字面量类型后生成错误类型?

TypeScript类型组合不符合预期的原因分析

给定以下TypeScript代码:

type Excuse<Excuses extends Record<string, string>> = {
  new (excuses: Excuses): keyof Excuses extends `${infer Key}`
    ? `${Key}: ${Excuses[Key]}`
    : never;
};

const helpingTheReindeer = {
  helping: 'the reindeer',
  differentKey: 'hello'
} as const;

declare const Excuse0: Excuse<typeof helpingTheReindeer>;
const excuse0 = new Excuse0({
  ...helpingTheReindeer,
});
type t0_actual = typeof excuse0;

实际得到的t0_actual类型是"helping: the reindeer" | "helping: hello" | "differentKey: the reindeer" | "differentKey: hello",而非预期的"helping: the reindeer" | "differentKey: hello"。即使对象被声明为常量,TypeScript依然会将所有键与所有值进行组合,以下是对这一类型系统行为的解释:

核心原因:类型层面的关联丢失

TypeScript处理联合类型时,不会自动维持键与对应值的绑定关系。在你的类型定义中:

keyof Excuses extends `${infer Key}` ? `${Key}: ${Excuses[Key]}` : never
  • keyof Excuses是联合类型"helping" | "differentKey",条件类型会对每个联合成员单独处理;
  • 当处理每个Key时,Excuses[Key]会被解析为所有键对应值的联合("the reindeer" | "hello"),而非当前Key对应的专属值;
  • 最终TypeScript会将每个键与所有值进行拼接,生成所有可能的组合,而非原对象的键值对映射。

修复方案:用映射类型绑定键值关系

要实现预期的一一对应键值对类型,需要通过映射类型遍历每个键并绑定对应的值,再将映射结果转为联合类型:

type Excuse<Excuses extends Record<string, string>> = {
  new (excuses: Excuses): { [K in keyof Excuses]: `${K}: ${Excuses[K]}` }[keyof Excuses];
};

这里:

  1. { [K in keyof Excuses]: ${K}: ${Excuses[K]} }生成一个与原对象结构一致的类型,每个键对应正确的拼接字符串;
  2. 通过[keyof Excuses]索引访问后,得到预期的联合类型"helping: the reindeer" | "differentKey: hello"。

内容的提问来源于stack exchange,提问作者Ermolaev.ID

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 11:58:11