@typescript-eslint/no-misused-spread

Disallow ... on values that do not spread the way they look

has suggestionsneeds types

Also called typescript-eslint/no-misused-spread, typescript/no-misused-spread

... in an object copies a value's own enumerable properties, and many values have none or the wrong ones. TypeScript accepts all of these:

SpreadWhat you get
A promise, a Map or a Set in an objectAn empty object.
Another iterable in an objectIts own properties, not the values it yields.
An array in an objectThe indexes as keys: { "0": .., "1": .. }.
A function without properties in an objectAn empty object. You probably meant to call it.
A class instance in an objectThe fields, without the class's methods and getters.
A class in an objectOnly its static properties.
A string in an array or a callCode points, which splits an emoji made of several of them.

Configure#

Off by default. This rule needs types, so turning it on makes bun lint type check your code first.

bunfig.toml
[lint.rules]
"@typescript-eslint/no-misused-spread" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-misused-spread" = ["error", {
  allow = [], # list of strings or objects
}]

Examples#

example.ts3 problems
declare function loadUser(): Promise<{ name: string }>;
const roles = new Map([["admin", true]]);
const tags = ["new", "sale"];

const user = { ...loadUser() };
const access = { ...roles };
const labels = { ...tags };
example.tsNo problems
declare function loadUser(): Promise<{ name: string }>;
const roles = new Map([["admin", true]]);
const tags = ["new", "sale"];

const user = { ...(await loadUser()) };
const access = Object.fromEntries(roles);
const labels = [...tags];

A class instance loses its methods:

example.ts1 problem
class Cart {
  items: string[] = [];
  count() {
    return this.items.length;
  }
}

const copy = { ...new Cart() };

A string in an array:

example.ts1 problem
function letters(name: string) {
  return [...name];
}

Intl.Segmenter splits a string into the characters a reader sees:

example.tsNo problems
function letters(name: string) {
  return Array.from(new Intl.Segmenter().segment(name), part => part.segment);
}

Options#

OptionDefaultWhat it does
allow[]Types you can spread. Each is a name, or an object that also says where the type comes from: { "from": "file", "name": .. }, { "from": "lib", "name": .. } or { "from": "package", "name": .., "package": .. }.

Not reported with allow: ["Cart"]:

example.tswith { "allow": ["Cart"] }No problems
class Cart {
  items: string[] = [];
  count() {
    return this.items.length;
  }
}

const copy = { ...new Cart() };