DEV Community

Cover image for JavaScript Array Reduce Doesn't Like Objects
bob.ts
bob.ts

Posted on

JavaScript Array Reduce Doesn't Like Objects

Recently, I was attempting to sum the values of an array that contained objects, like so ...

const pie = [
  { data: 10, color: "#ECD078" },
  { data: 20, color: "#D95B43" },
  { data: 10, color: "#C02942" },
  { data: 10, color: "#542437" },
  { data: 10, color: "#53777A" }
];
Enter fullscreen mode Exit fullscreen mode

I simply wanted the sum of the data keys. I tried ...

const pieTotal = pie.reduce((a, b) => a.data + b.data, 0);
Enter fullscreen mode Exit fullscreen mode

... and kept getting NaN as a result. When I got some add consoles.log values I decided to dig into reduce and quickly found Array.prototype.reduce(), which showed the (a, b) were not actually two values as I had assumed, but (accumulator, currentValue).

That's what I get for assuming from a Stack Overflow example.

Here's the working reduce code ...

const pieTotal =  pie.reduce((a, b) => a + b.data, 0);
Enter fullscreen mode Exit fullscreen mode

Just a reminder to myself to never assume functionality and to regularly check the documentation.

Top comments (9)

Collapse
 
jimmymcbride profile image
Jimmy McBride

I put your example in a TypeScript function to see what was going on.

interface Pie {
  data: number;
  color: string;
}

const pie: Pie[] = [
  { data: 10, color: "#ECD078" },
  { data: 20, color: "#D95B43" },
  { data: 10, color: "#C02942" },
  { data: 10, color: "#542437" },
  { data: 10, color: "#53777A" },
];

const pieTotal = pie.reduce((a, b) => a + b.data, 0);

console.log(pieTotal);

That gave me the correct answer of 60. When I hover over the arguments, a and b, I can see the types that the reducer function is passing them. When I hover over a, it says it's type is a number, but when I hover over b, it says its type is Pie.

To play around with this further, I added an id key/value pair to the Pie object.

interface Pie {
  id: number;
  data: number;
  color: string;
}

const pie: Pie[] = [
  { id: 1, data: 10, color: "#ECD078" },
  { id: 2, data: 20, color: "#D95B43" },
  { id: 3, data: 10, color: "#C02942" },
  { id: 4, data: 10, color: "#542437" },
  { id: 5, data: 10, color: "#53777A" },
];

const pieTotal = pie.reduce((a, b) => a + b.id, 0);

console.log(pieTotal);

This gave me the correct answer of 15.

When I changed b to select the color key, which is a string I got an error and this is what I think is the important part of that error:

array: Pie[]) => number, initialValue: number): number', gave the following error.
Type 'string' is not assignable to type 'number'.

So this is what it seems like to me:

I think the first argument a has to be a number to work. So it's automatically typed as any key of the object that is a number.

The second argument b is typed as the object that is in our Pie array, so you can select any key that's value is a number and that is going to be the key that a is. But if you do b.color it's going to error because you can reduce strings like that.

Hope this helps! :)

Collapse
 
jimmymcbride profile image
Jimmy McBride

The first thing I noticed when I pasted this in a ts file and typed the array, was that const pieTotal = pie.reduce((a, b) => a.data + b.data, 0); had an error on a.data that said: Property 'data' does not exist on type 'number'. Which is what eventually lead me to try what I did above.

Collapse
 
kosich profile image
Kostia Palchyk

Maybe, the (a, b) => ... notation was confusing β€” it kinda implies that a and b are array values, while actually a is the accumulator and b is the current value.

So nowadays I define reduce fn params as acc and curr:

[ /**/ ].reduce((acc, curr) => acc + curr.data, 0)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rfornal profile image
bob.ts

Excellent thought. I'll adjust my code this way in the future!

Collapse
 
jimmymcbride profile image
Jimmy McBride

I think I just said what this guy pointed out already. Haha

Collapse
 
sabbin profile image
Sabin Pandelovitch

"JavaScript reduce doesn't like objects".... Of course it doesn't, it's an array prototype method.... Second you are iterating through an array of objects. Third since when second guessing is a method of programming.... Was this post a like a journal entry? Cause it would make more sense

Collapse
 
jimmymcbride profile image
Jimmy McBride

First) JavaScript loves objects. It makes sense that a reduce function would be able to handle objects since that's what everything is in JavaScript anyways. Why cut out your first-class citizens?

Second) Yup. Arrays are objects too. What's the problem with iterating through a list of objects? Often times you will get back an array of objects from a back end API anyways. It would be pretty annoying if you could not reduce an array of objects by a key in the object type you were iterating over.

Thirdly) Second-guessing is a beautiful method when it comes to programming. Doubt is a very important quality of a scientific, empirical thinker.

Collapse
 
sabbin profile image
Sabin Pandelovitch • Edited

I didn't stated that Javascript doesn't like objects... I quoted the title of the article as it's wrong, it's just like saying "Javascript string split doesn't like arrays"

Array are objects too, yes indeed.

Assume the following example

const array = [1, 2, 3];
const object = { a: 1, b: 2, c: 3 };

console.log(array.constructor); //array
console.log(object.constructor); //object

array.reduce((acc, val) => acc + val, 0); //6
object.reduce((acc, val) => acc + val, 0); //error

array.a = 4;

console.log(array.constructor); //still array
array.reduce((acc, val) => acc + val, 0); //still 6
console.log(Object.keys(array)); // ["0", "1", "2", "a"]

So yes, arrays are objects so therefore they can access object prototype methods, but not all objects are arrays so they cannot access the array prototype methods...

"What's the problem with iterating through a list of objects?"

There is no problem with this, I was trying to state that the title is misleading again. The object is not reduced, the list objects is reduced and the callback of the method is handling the object... The callback of a method is not the method itself...

Last but not least... You can write code with your hands tided around your back blindfolded in a random PL. Does that make it efficient? is it good?

Doubt can be a very important quality indeed, but I don't think here is the case. You are working with something that has been written already, what can you doubt here?

If you install a new package or start working with a new library, you start coding in the dark? Doesn't the documentation come in the first place?

Collapse
 
rfornal profile image
bob.ts

It is more like a journal entry. Something to remind me not to do that again.