Skip to content

noMisusedSpread (JavaScript)

Language JavaScript (and super languages)
biome.json
{
"linter": {
"rules": {
"nursery": {
"noMisusedSpread": "error"
}
}
}
}

Disallow spreading values in ways that can cause unexpected results.

The spread syntax (...) copies values into a new array, object, or list of arguments. For some values the copy doesn’t contain what you might expect:

  • Spreading a string into an array, as in [...text], splits it into Unicode code points. Characters made of several code points, such as many emoji, end up split into separate pieces.
  • Spreading a Promise into an object copies nothing. The value it resolves to is only available after awaiting it.
  • Spreading a function into an object copies nothing, unless the function has properties of its own.
  • Spreading a Map into an object creates an empty object, because the entries of a map aren’t properties.
  • Spreading an array into an object creates properties named after its indexes, such as 0 and 1.
  • Spreading another iterable value, such as a Set, into an object doesn’t copy the values it contains.
  • Spreading a class instance into an object creates a plain object without the methods and getters of the class.
  • Spreading a class into an object only copies its static properties.

This rule uses type information to find these values.

invalid-string.ts
declare const text: string;
const characters = [...text];
/invalid-string.ts:2:24 lint/nursery/noMisusedSpread ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ Spreading a string splits it into code points, which can break characters apart.

1 │ declare const text: string;
> 2 │ const characters = [...text];
│ ^^^^
3 │

ℹ Characters made of several code points, such as many emoji and some letters with accents, are split into separate pieces.

ℹ Use Intl.Segmenter to split the string into the characters that a reader sees. If the string only contains simple characters, suppress this diagnostic.

ℹ 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.

invalid-promise.ts
declare function getUser(): Promise<{ name: string }>;
const user = { ...getUser() };
/invalid-promise.ts:2:19 lint/nursery/noMisusedSpread ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ Spreading a Promise into an object copies nothing.

1 │ declare function getUser(): Promise<{ name: string }>;
> 2 │ const user = { ...getUser() };
│ ^^^^^^^^^
3 │

ℹ The value of a Promise is only available after it resolves.

ℹ Did you forget to await it?

ℹ 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.

invalid-map.ts
declare const scores: Map<string, number>;
const copy = { ...scores };
/invalid-map.ts:2:19 lint/nursery/noMisusedSpread ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ Spreading a map into an object creates an empty object.

1 │ declare const scores: Map<string, number>;
> 2 │ const copy = { ...scores };
│ ^^^^^^
3 │

ℹ The entries of a map aren't properties, so they aren't copied.

ℹ To turn the entries of a Map into properties, use Object.fromEntries().

ℹ 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.

invalid-class-instance.ts
class Point {
constructor(public x: number, public y: number) {}
length() {
return Math.hypot(this.x, this.y);
}
}
const copy = { ...new Point(1, 2) };
/invalid-class-instance.ts:7:19 lint/nursery/noMisusedSpread ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ Spreading a class instance into an object loses the methods of its class.

5 │ }
6 │ }
> 7 │ const copy = { ...new Point(1, 2) };
│ ^^^^^^^^^^^^^^^
8 │

ℹ Only the own properties of the instance are copied into a plain object. Methods and getters of the class aren't.

ℹ Keep using the instance, or create a new one with the class.

ℹ 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.

valid.ts
declare const text: string;
const words = text.split(" ");
declare const items: number[];
const copy = [...items];
declare function getUser(): Promise<{ name: string }>;
async function loadUser() {
return { ...(await getUser()) };
}
declare const scores: Map<string, number>;
const entries = Object.fromEntries(scores);