Reputation: 63
I have the following code:
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[] = [/* Some data */];
const availablePromos: ICartTotal[] = promo.reduce((acc, cur) => {
return [
...acc,
{
type: "discount",
title: cur.label,
price: cur.total
}
]
}, []);
The code above throws two erros:
availablePromos
definition:const availablePromos: ICartTotal[]
Type 'ICartItemResponse' is missing the following properties from type 'ICartTotal[]': length, pop, push, concat, and 29 more.
acc
and cur
, respectively):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'.
I notice it was possible to "solve" both errors in two different ways:
(acc: ICartTotal[], cur)
Notice that if I specify the type of the current value (which is indeed being infered) with the same infered type. Throws the following error:
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: ICartTotal[], cur: ICartItemResponse) => { type: string; 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 'ICartTotal[]': length, pop, push, concat, and 29 more.
Overload 2 of 3, '(callbackfn: (previousValue: ICartTotal[], currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => ICartTotal[], initialValue: ICartTotal[]): ICartTotal[]', gave the following error.
Argument of type '(acc: ICartTotal[], cur: ICartItemResponse) => { type: string; title: string; price: number; }[]' is not assignable to parameter of type '(previousValue: ICartTotal[], currentValue: ICartItemResponse, currentIndex: number, array: ICartItemResponse[]) => ICartTotal[]'.
Type '{ type: string; title: string; price: number; }[]' is not assignable to type 'ICartTotal[]'.
Type '{ type: string; title: string; price: number; }' is not assignable to type 'ICartTotal'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type 'ICartTotalType'.
[] as ICarttotal[]
This one works fine, but if I also combine this with the first approach, throws the same error as in the last point.
My question is: In order to return a variable with a different type than the variable being reduced, is it only necessary to assert the type of the initial value on a reducer if the arguments are already being infered?
Thank you in advance!
Upvotes: 0
Views: 170
Reputation: 187262
With reduce
I often find it best to explicitly pass the result type as the generic type parameter. Then the initial argument and the callback function all get typed properly for you. I find this often removes a great deal of the type errors you usually get with calling reduce
because Typescript knows exactly how the completed reduce result is typed before it starts.
const availablePromos = promo.reduce<ICartTotal[]>((acc, cur) => {
return [
...acc,
{
type: "discount",
title: cur.label,
price: cur.total
}
]
}, [])
// availablePromos is ICartTotal[]
Upvotes: 2