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 } ] }, []);
遇到的类型错误
availablePromos定义处的错误:
const availablePromos: ICartTotal[] Type 'ICartItemResponse' is missing the following properties from type 'ICartTotal[]': length, pop, push, concat, and 29 more.
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
相关产品推荐
相关产品推荐

