@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:
| Spread | What you get |
|---|---|
A promise, a Map or a Set in an object | An empty object. |
| Another iterable in an object | Its own properties, not the values it yields. |
| An array in an object | The indexes as keys: { "0": .., "1": .. }. |
| A function without properties in an object | An empty object. You probably meant to call it. |
| A class instance in an object | The fields, without the class's methods and getters. |
| A class in an object | Only its static properties. |
| A string in an array or a call | Code 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()Using the spread operator on Promise in an object can cause unexpected behavior. Did you forget to await the promise? };
const access = { ...rolesUsing the spread operator on a Map in an object will result in an empty object. Did you mean to use Object.fromEntries(map) instead? };
const labels = { ...tagsUsing the spread operator on an array in an object will result in a list of indices. };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()Using the spread operator on class instances will lose their class prototype. };A string in an array:
example.ts1 problem
function letters(name: string) {
return [...nameUsing the spread operator on a string can mishandle special characters, as can .split("").... produces Unicode code points, which will decompose complex emojis into individual emojis.split("") produces UTF-16 code units, which breaks rich characters in many languagesConsider using Intl.Segmenter for locale-aware string decomposition.Otherwise, if you don't need to preserve emojis or other non-Ascii characters, disable this lint rule on this line or configure the allow rule option.];
}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#
| Option | Default | What 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 problemsclass Cart {
items: string[] = [];
count() {
return this.items.length;
}
}
const copy = { ...new Cart() };