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

如何解决TS2590:表达式生成的联合类型过于复杂无法表示

问题背景

我把应用中的API错误逻辑简化成如下代码,运行时会抛出错误:Expression produces a union type that is too complex to represent.

核心问题
  1. 如何避免该错误?(缩小API规模不可行)
  2. 如何让TypeScript忽略该错误/提高联合类型上限?
    3.(可选)该错误为何会发生?我了解到联合类型上限为100000,但示例代码仅包含5种错误类型,其中第一种有10个错误,不清楚具体原因。
已尝试的无效方法
  • 使用$Values替代ValuesType
  • 更换不同的TypeScript 4.x版本(无法降级到3.4)
  • 使用类型别名
  • 使用唯一错误码
  • 用$Values<typeof ErrType1 & typeof ErrType2>替代$Values<typeof ErrType1> | $Values<typeof ErrType2>
示例代码
import type { $Values } from 'utility-types';

const MESSAGES = {
  msg1: 'msg1',
  msg2: 'msg2',
  msg3: 'msg3',
  msg4: 'msg4',
  msg5: 'msg5',
} as const;

const ErrType1 = {
  Err_1_1: {
    code: 1,
  },
  Err_1_2: {
    code: 2,
  },
  Err_1_3: {
    code: 3,
  },
  Err_1_4: {
    code: 4,
  },
  Err_1_5: {
    code: 5,
  },
  Err_1_6: {
    code: 6,
  },
  Err_1_7: {
    code: 7,
  },
  Err_1_8: {
    code: 8,
  },
  Err_1_9: {
    code: 9,
  },
  Err_1_10: {
    code: 10,
  },
} as const;

const ErrType2 = {
  Err_2_1: {
    code: 1,
  },
} as const;

const ErrType3 = {
  Err_3_1: {
    code: 1,
  },
} as const;

const ErrType4 = {
  Err_4_1: {
    code: 1,
  },
} as const;

const ErrType5 = {
  Err_5_1: {
    code: 1,
  },
} as const;

type ApiErrors = {
  [MESSAGES.msg1]: $Values<typeof ErrType1>;
  [MESSAGES.msg2]: $Values<typeof ErrType1> | $Values<typeof ErrType2>;
  [MESSAGES.msg3]: $Values<typeof ErrType1> | $Values<typeof ErrType3>;
  [MESSAGES.msg4]: $Values<typeof ErrType1> | $Values<typeof ErrType4>;
  [MESSAGES.msg5]: $Values<typeof ErrType1> | $Values<typeof ErrType5>;
};

type Response<Message extends $Values<typeof MESSAGES>> = {
  error: ApiErrors[Message];
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function test<Message extends $Values<typeof MESSAGES>>(): Response<Message> {
  return {
    error: ErrType1.Err_1_1,
  };
}

解决方案

1. 避免错误的可行方法

核心是减少TypeScript需要计算的联合类型复杂度,以下是几种有效方案:

方案一:抽离公共联合类型,避免重复展开

把重复出现的$Values<typeof ErrType1>抽成公共类型别名,复用后减少TypeScript重复计算同一联合类型的次数:

type BaseErr = $Values<typeof ErrType1>;

type ApiErrors = {
  [MESSAGES.msg1]: BaseErr;
  [MESSAGES.msg2]: BaseErr | $Values<typeof ErrType2>;
  [MESSAGES.msg3]: BaseErr | $Values<typeof ErrType3>;
  [MESSAGES.msg4]: BaseErr | $Values<typeof ErrType4>;
  [MESSAGES.msg5]: BaseErr | $Values<typeof ErrType5>;
};

方案二:用条件类型替代索引访问

修改Response类型,通过条件类型直接映射消息与错误类型,降低泛型推导时的类型展开复杂度:

type Response<Message extends $Values<typeof MESSAGES>> = {
  error: Message extends typeof MESSAGES.msg1 
    ? $Values<typeof ErrType1>
    : Message extends typeof MESSAGES.msg2
      ? $Values<typeof ErrType1> | $Values<typeof ErrType2>
      : Message extends typeof MESSAGES.msg3
        ? $Values<typeof ErrType1> | $Values<typeof ErrType3>
        : Message extends typeof MESSAGES.msg4
          ? $Values<typeof ErrType1> | $Values<typeof ErrType4>
          : $Values<typeof ErrType1> | $Values<typeof ErrType5>;
};

方案三:放宽类型约束(牺牲部分精确性)

如果不需要极致的类型精确性,可以将错误类型合并为一个通用联合类型:

type ApiErrorUnion = $Values<typeof ErrType1> | $Values<typeof ErrType2> | $Values<typeof ErrType3> | $Values<typeof ErrType4> | $Values<typeof ErrType5>;

type Response<Message extends $Values<typeof MESSAGES>> = {
  error: ApiErrorUnion;
};

2. 忽略错误或调整TypeScript限制

忽略单个错误

在报错代码行上方添加注释,精准忽略该错误:

// @ts-expect-error
function test<Message extends $Values<typeof MESSAGES>>(): Response<Message> {
  return {
    error: ErrType1.Err_1_1,
  };
}

不推荐使用// @ts-ignore,它会忽略该行所有错误。

降低泛型检查严格度

TypeScript没有公开配置项直接提高联合类型上限,但可以通过编译选项--noStrictGenericChecks降低泛型检查的严格程度,间接减少这类错误的触发概率。注意:该选项会放宽其他泛型约束,需谨慎使用。

3. 错误发生的原因

你了解到的100000是TypeScript对显式声明的联合类型的节点上限,但你的问题出在泛型推导时的隐式类型展开:
当TypeScript处理Response<Message>时,需要为Message的每个可能值(5个)展开对应的ApiErrors[Message]类型,而每个ApiErrors[Message]又包含10个成员的BaseErr联合类型。TypeScript在推导泛型返回值时,会尝试将所有可能的组合展开成一个巨大的隐式联合类型,这个过程中生成的中间类型节点数远超预期,触发了内部的复杂度阈值,导致报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:50:21