unicorn/no-useless-iterator-to-array

Disallow .toArray() on an iterator where the iterator itself works

fixable

iterator.toArray() walks the whole iterator and allocates an array. The array is wasted if the next step takes any iterable, or calls a method that iterators have too.

The rule reports .toArray():

  • in for...of, yield* and a spread into an array or a call
  • as the argument of new Set(), new Map(), new WeakSet(), new WeakMap() or a typed array constructor
  • as the argument of Array.from(), Object.fromEntries(), Promise.all(), Promise.allSettled(), Promise.any() or Promise.race()
  • before .every(), .find(), .forEach(), .some() or .reduce() with an initial value

--fix removes the .toArray(). Before an iterator method and in the Promise methods, only --fix-suggestions does.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"unicorn/no-useless-iterator-to-array" = "error" # or "warn"

Examples#

example.js4 problems
for (const name of users.keys().toArray()) {
  console.log(name);
}

const ids = new Set(users.values().map(user => user.id).toArray());
const list = [...users.values().toArray()];
const hasAdmin = users.values().toArray().some(user => user.admin);
example.jsNo problems
for (const name of users.keys()) {
  console.log(name);
}

const ids = new Set(users.values().map(user => user.id));
const list = [...users.values()];
const hasAdmin = users.values().some(user => user.admin);

Methods that only arrays have still need the array, and so does a callback that takes the array as its third parameter:

example.jsNo problems
const sorted = users.values().toArray().sort(byName);

const isUnique = users.values().toArray().every((user, index, all) => all.indexOf(user) === index);

When not to use it#

The rule can't see types, so it reports every .toArray() call without arguments in these places. Turn it off if you use a library with its own toArray() on objects that aren't iterable.