RSPEC-6959 - JS/TS Array.reduce()

Similar issue as described here: False Positive Array.reduce() - Rules and Languages / Report False-positive / False-negative… - Sonar Community

However, I wanted to add my specific, real-world use case where I think compliance with this rule ends up making the code less readable and harder to maintain.

Given an array of numbers, I have to subtract each number in order. For example, [100, 45, 5, 15] should produce 35 ; i.e. 100 - 45 - 5 - 15 = 35. This is simple to do with Array.reduce()

[100, 45, 5, 15].reduce((a, b) => a - b); // 35

If I were to give it a starting value, what should that value be? I can’t use 0 nor could use the first element in the array.

const operands = [100, 45, 5, 15];
operands.reduce((a, b) => a - b, 0); // -165
operands.reduce((a, b) => a - b, operands[0]) // -65

Basically, in order to do this right, I have to remove the first element from my array, and pass that as the initial value:

const operands = [100, 45, 5, 15];
const firstOperand = operands.shift();
operands.reduce((a, b) => a - b, firstOperand); // 35

To me, this adds unnecessary overhead and to something that already works correctly. Not to mention, I had to mutate my original array to get this to work. Naturally I could get around that by copying the array or by chaining a filter before the reduce, but again, this is just more work and ends up being more confusing than something that works out of the box.

A for loop can be considered:

let result = operands[0];
for (let i = 1; i < operands.length; i++) {
    result -= operands[i];
}

or a numerically different (different floating point inaccuracies) approach that sums the elements first:

const result = 2 * operands[0] - operands.reduce((a, b) => a + b, 0);

While I appreciate the alternative approaches, they do not address the original intent of my post, which is that in order to avoid the rule violation, I have to make my code more complex and less readable. This in turn can lead to a higher risk of incorrect or faulty outcomes.

Hi Seth,

Thanks for sharing. Whilst, I see your use-case, the operation you are applying isn’t homogenous. You treat the first element differently than the other elements of the array and the reason it works is the non-obvious initial value (operands[0] vs let’s say 0). The rule exists to prevent subtle bugs and edge cases — for example, when the array might be empty or when the first element’s type isn’t guaranteed.

That being said, in order to make your code more explicit, I would suggest replacing with:

const operands = [100, 45, 5, 15];
const result = operands.slice(1).reduce((a, b) => a - b, operands[0]);

This way, the logic is clear to anyone reading the code, and the original array remains unchanged.

Kind regards,

Michal

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.