noMapSpread (JavaScript)
Summary
Section titled “Summary”- Rule available since:
v2.6.5 - Diagnostic Category:
lint/nursery/noMapSpread - This rule has an unsafe fix.
- The default severity of this rule is warning.
- Sources:
- Same as
oxc/no-map-spread
- Same as
How to configure
Section titled “How to configure”{ "linter": { "rules": { "nursery": { "noMapSpread": "error" } } }}Description
Section titled “Description”Disallow spreading objects or arrays in the values returned by map() and flatMap() callbacks.
A spread (...) inside an object or array literal creates a new object or
array and copies every property or element into it. When the callback of
map() or flatMap() does this, the copy happens once for each item in the
array, which is slow and uses extra memory for large arrays.
When it’s fine to change the original items, use
Object.assign()
or assign the new properties directly. For arrays, add the new elements with
push().
Copying is still useful when other code needs the original items to stay
unchanged. To avoid reporting those cases, the rule ignores map() and
flatMap() calls on:
- arrays read from
this, such asthis.items.map(...); - variables that are read again after the call (see the
ignoreRereadsoption); - function parameters (see the
ignoreArgsoption).
The rule follows variables that the callback declares and returns, so it also
reports const copy = { ...item }; return copy;.
The fix replaces an object that starts with a spread and has at least one
other property with a call to Object.assign(). This changes the first
spread object in place, so the fix is unsafe. The fix isn’t offered for an
object that only contains a spread, such as { ...item }, or for an object
that contains comments.
Examples
Section titled “Examples”Invalid
Section titled “Invalid”const users = getUsers();const rows = users.map((user) => ({ ...user, role: getRole(user) }));code-block.js:2:35 lint/nursery/noMapSpread FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This object spread copies an object for each item in the map() callback.
1 │ const users = getUsers();
> 2 │ const rows = users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │
ℹ The callback runs once for each item in the array.
1 │ const users = getUsers();
> 2 │ const rows = users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^
3 │
ℹ A spread creates a new object and copies every property into it. Doing this for each item is slow and uses extra memory for large arrays.
ℹ If it's fine to change the original items, add the properties with Object.assign() or assign them directly. Keep the spread if other code needs the original items to stay unchanged.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
ℹ Unsafe fix: Use Object.assign() instead.
1 1 │ const users = getUsers();
2 │ - const·rows·=·users.map((user)·=>·({·...user,·role:·getRole(user)·}));
2 │ + const·rows·=·users.map((user)·=>·Object.assign(user,·{·role:·getRole(user)·}));
3 3 │
const groups = getGroups();const lists = groups.flatMap((group) => [...group.members, group.owner]);code-block.js:2:41 lint/nursery/noMapSpread ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This array spread copies an array for each item in the flatMap() callback.
1 │ const groups = getGroups();
> 2 │ const lists = groups.flatMap((group) => [...group.members, group.owner]);
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │
ℹ The callback runs once for each item in the array.
1 │ const groups = getGroups();
> 2 │ const lists = groups.flatMap((group) => [...group.members, group.owner]);
│ ^^^^^^^
3 │
ℹ A spread creates a new array and copies every element into it. Doing this for each item is slow and uses extra memory for large arrays.
ℹ If it's fine to change the original arrays, add the elements with push(). Keep the spread if other code needs the original arrays to stay unchanged.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
const users = getUsers();const rows = users.map((user) => Object.assign(user, { role: getRole(user) }));
class UsersStore { #users = []; get users() { // Each caller gets its own copies, so changing them can't change the store. return this.#users.map((user) => ({ ...user })); }}Options
Section titled “Options”ignoreRereads
Section titled “ignoreRereads”Default: true
Ignores map() and flatMap() calls on a variable that is read again after
the call. Code that reads the original array later may rely on the copies to
keep the original items unchanged.
const users = getUsers();const rows = users.map((user) => ({ ...user, role: getRole(user) }));console.log(users);Set it to false to report these calls too.
{ "linter": { "rules": { "nursery": { "noMapSpread": { "level": "on", "options": { "ignoreRereads": false } } } } }}const users = getUsers();const rows = users.map((user) => ({ ...user, role: getRole(user) }));console.log(users);code-block.js:2:35 lint/nursery/noMapSpread FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This object spread copies an object for each item in the map() callback.
1 │ const users = getUsers();
> 2 │ const rows = users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │ console.log(users);
4 │
ℹ The callback runs once for each item in the array.
1 │ const users = getUsers();
> 2 │ const rows = users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^
3 │ console.log(users);
4 │
ℹ A spread creates a new object and copies every property into it. Doing this for each item is slow and uses extra memory for large arrays.
ℹ If it's fine to change the original items, add the properties with Object.assign() or assign them directly. Keep the spread if other code needs the original items to stay unchanged.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
ℹ Unsafe fix: Use Object.assign() instead.
1 1 │ const users = getUsers();
2 │ - const·rows·=·users.map((user)·=>·({·...user,·role:·getRole(user)·}));
2 │ + const·rows·=·users.map((user)·=>·Object.assign(user,·{·role:·getRole(user)·}));
3 3 │ console.log(users);
4 4 │
ignoreArgs
Section titled “ignoreArgs”Default: true
Ignores map() and flatMap() calls on a function parameter. The caller
owns the array, so changing its items in place could affect code outside the
function.
function withRoles(users) { return users.map((user) => ({ ...user, role: getRole(user) }));}Set it to false to report these calls too.
{ "linter": { "rules": { "nursery": { "noMapSpread": { "level": "on", "options": { "ignoreArgs": false } } } } }}function withRoles(users) { return users.map((user) => ({ ...user, role: getRole(user) }));}code-block.js:2:31 lint/nursery/noMapSpread FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This object spread copies an object for each item in the map() callback.
1 │ function withRoles(users) {
> 2 │ return users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │ }
4 │
ℹ The callback runs once for each item in the array.
1 │ function withRoles(users) {
> 2 │ return users.map((user) => ({ ...user, role: getRole(user) }));
│ ^^^
3 │ }
4 │
ℹ A spread creates a new object and copies every property into it. Doing this for each item is slow and uses extra memory for large arrays.
ℹ If it's fine to change the original items, add the properties with Object.assign() or assign them directly. Keep the spread if other code needs the original items to stay unchanged.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
ℹ Unsafe fix: Use Object.assign() instead.
1 1 │ function withRoles(users) {
2 │ - ··return·users.map((user)·=>·({·...user,·role:·getRole(user)·}));
2 │ + ··return·users.map((user)·=>·Object.assign(user,·{·role:·getRole(user)·}));
3 3 │ }
4 4 │
See Also
Section titled “See Also”- If you want to disallow spreading the accumulator of
reduce(), seenoAccumulatingSpread.
Related links
Section titled “Related links”Copyright (c) 2023-present Biome Developers and Contributors.