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

TypeScript中Reduce返回不同类型变量的正确方式及疑问

TypeScript中使用reduce转换不同类型数组的类型问题

问题场景

我试图用reduce把ICartItemResponse数组转换为ICartTotal数组,代码如下:

interface ICartItemResponse {
    sku: string;
    priceChange: boolean;
    price: number;
    total: number;
    label: string;
}

type TCartTotalType = "shipping" | "tax" | "discount";

interface ICartTotal {
    type: TCartTotalType;
    title: string;
    price: number;
};

const promo: ICartItemResponse[] = [/* 测试数据 */];

const availablePromos: ICartTotal[] = promo.reduce((acc, cur) => {
    return [
        ...acc,
        {
            type: "discount",
            title: cur.label,
            price: cur.total
        }
    ]
}, []);

遇到的类型错误

  1. availablePromos定义处的错误:
const availablePromos: ICartTotal[]
Type 'ICartItemResponse' is missing the following properties from type 'ICartTotal[]': length, pop, push, concat, and 29 more.
  1. reduce参数处的错误:
No overload matches this call.
  Overload 1 of 3, '(callbackfn: (previousValue: ICartItemResponse, currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => ICartItemResponse, initialValue: ICartItemResponse): ICartItemResponse', gave the following error.
    Argument of type '(acc: never[], cur: ICartItemResponse) => { type: "discount"; title: string; price: number; }[]' is not assignable to parameter of type '(previousValue: ICartItemResponse, currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => ICartItemResponse'.
      Types of parameters 'acc' and 'previousValue' are incompatible.
        Type 'ICartItemResponse' is missing the following properties from type 'never[]': length, pop, push, concat, and 29 more.
  Overload 2 of 3, '(callbackfn: (previousValue: never[], currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => never[], initialValue: never[]): never[]', gave the following error.
    Argument of type '(acc: never[], cur: ICartItemResponse) => { type: "discount"; title: string; price: number; }[]' is not assignable to parameter of type '(previousValue: never[], currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => never[]'.
      Type '{ type: "discount"; title: string; price: number; }[]' is not assignable to type 'never[]'.
        Type '{ type: "discount"; title: string; price: number; }' is not assignable to type 'never'.

错误原因

TypeScript对reduce的类型推断逻辑是:如果没有明确指定返回类型,会尝试根据原数组类型和初始值推断。这里初始值[]被推断为never[],而回调函数返回的是包含ICartTotal结构的数组,和原数组的ICartItemResponse类型不匹配,导致类型冲突。

解决方案

方法1:断言初始值类型(最简便)

直接给初始值[]断言为ICartTotal[],TypeScript会自动推断出acc的类型是ICartTotal[],同时匹配返回值类型:

const availablePromos: ICartTotal[] = promo.reduce((acc, cur) => {
    return [
        ...acc,
        {
            type: "discount",
            title: cur.label,
            price: cur.total
        }
    ]
}, [] as ICartTotal[]);

方法2:显式指定reduce的泛型参数

通过给reduce指定泛型参数,明确返回值的类型,同样可以解决问题:

const availablePromos: ICartTotal[] = promo.reduce<ICartTotal[]>((acc, cur) => {
    return [
        ...acc,
        {
            type: "discount",
            title: cur.label,
            price: cur.total
        }
    ]
}, []);

核心问题解答

当使用reduce返回与原数组不同类型的结果时,只需断言初始值的类型就足够。因为TypeScript会根据初始值的类型自动推断出累加器acc的类型,以及整个reduce的返回类型。

如果同时指定acc的类型和断言初始值,反而可能触发类型错误——这是因为当你显式指定acc的类型后,初始值的类型需要严格匹配该类型,而如果写法不当(比如重复定义类型导致冲突)就会报错。实际上只要初始值的断言正确,acc的类型会被自动正确推断,无需额外指定。

内容的提问来源于stack exchange,提问作者Yair Rodríguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:30:56