oxc/no-accumulating-spread

Disallow spreading the accumulator in reduce() and in loops

[...result, item] copies everything in result into a new array. Doing that once per item copies 1 element, then 2, then 3. For 10,000 items, that's about 50 million copied elements instead of 10,000 pushes. Objects built with { ...result, [key]: value } cost the same.

The rule reports:

  • In the callback of reduce() or reduceRight(): a spread of the first parameter, when the callback has exactly two parameters.
  • In a loop: result = [...result, item] or result = { ...result, ... }, when result is a let declared outside the loop.

Change the accumulator in place instead. When the initial value is a fresh [] or {}, no other code holds it, so nothing else sees the change.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"oxc/no-accumulating-spread" = "error" # or "warn"

Examples#

example.js2 problems
const names = users.reduce((result, user) => [...result, user.name], []);

const byId = users.reduce((result, user) => ({ ...result, [user.id]: user }), {});
example.js1 problem
let active = [];
for (const user of users) {
  if (user.isActive) {
    active = [...active, user];
  }
}
example.jsNo problems
const names = users.map((user) => user.name);

const byId = users.reduce((result, user) => {
  result[user.id] = user;
  return result;
}, {});

const active = [];
for (const user of users) {
  if (user.isActive) {
    active.push(user);
  }
}

When not to use it#

For a handful of items, the cost doesn't matter. If you like how the spread reads and your lists are small, leave the rule off.