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

如何正确处理TypeScript中reduce处理联合类型数组的类型问题?

解决TypeScript中数组联合类型的reduce类型不兼容问题

问题背景

现有segregateIds函数,用于根据string-to-boolean映射表,将string[]或number[]类型的ID列表分为两组。实现后出现TypeScript错误:reduce无法兼容string[]或number[]的联合类型输入。要求不能将类型改为Array<string|number>,需解决该TS错误。

原错误代码:

const segregateIds = (
  ids: string[] | number[],
  optionsById: Record<string, boolean>,
): { correctIds: string[] | number[]; incorrectIds: string[] | number[] } => {

  return ids.reduce<{ correctIds: string[] | number[]; incorrectIds: string[] | number[] }>(
    (accum: { correctIds: string[] | number[]; incorrectIds: string[] | number[] }, id: string | number) => {
      if (optionsById[id]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }

      return accum;
    },
    {
      correctIds: [],
      incorrectIds: [],
    }
  );
};

解决方案:泛型约束保证类型一致性

修改后的代码:

const segregateIds = <T extends string | number>(
  ids: T[],
  optionsById: Record<string, boolean>,
): { correctIds: T[]; incorrectIds: T[] } => {
  return ids.reduce(
    (accum, id) => {
      if (optionsById[String(id)]) {
        accum.correctIds.push(id);
      } else {
        accum.incorrectIds.push(id);
      }
      return accum;
    },
    { correctIds: [] as T[], incorrectIds: [] as T[] }
  );
};

关键修改说明

  • 引入泛型T extends string | number,约束输入的ID类型为纯string或纯number,确保输入数组是string[]或number[],而非混合类型,完全匹配原需求。
  • 初始值数组通过as T[]断言类型,让TypeScript明确两个结果数组的类型与输入数组完全一致,解决reduce初始值的类型推断歧义。
  • 访问optionsById时,用String(id)统一转换ID为字符串,适配Record<string, boolean>的键类型,同时消除number类型作为键时的隐式转换警告。

原错误原因

原代码中,ids是联合类型string[] | number[],reduce的初始值数组被TypeScript推断为never[](无法确定具体类型);同时,id是string | number类型,往correctIds/incorrectIds(string[] | number[])中push时,TypeScript无法保证类型匹配(比如correctIds是string[]但id是number),因此抛出类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 21:39:36