An object changes somewhere you never touched
“Defaults, cached responses, or React state change between requests or renders. One user's header shows up on another user's call, or a list is re-sorted in a component that never sorted it.”
THE PRINCIPLE
Data you did not create is read-only to you. Copy exactly what you change, and make shared values (defaults, caches, state) immutable by construction.
FIRST MOVES
- Find the writer: Object.freeze the suspect object in development (freeze is shallow, so freeze nested parts too) and the TypeError in strict code points at the mutation.
- Audit copies: { ...obj } shares nested objects, Array(n).fill({}) shares one object n times, and module-level defaults are shared by every request.
- Replace mutating array methods on shared data (sort, reverse, splice) with toSorted, toReversed, toSpliced and with.
- Use structuredClone for a deep copy of plain data; it keeps Dates, Maps, Sets and cycles, but drops prototypes and private fields and throws on functions.
- Type shared values as readonly / ReadonlyArray so new mutations fail at compile time.
TOOLS: THEN → NOW
JSON.parse(JSON.stringify(x)) for deep copiesstructuredClone, which also preserves Date, Map, Set and circular references
In-place sort/splice/reversetoSorted/toSpliced/toReversed/with (ES2023)
Immutability by conventionreadonly types, Object.freeze in development, or Immer for nested updates
PATTERN SNAPSHOT
const DEFAULTS: { retries: number; headers: Record<string, string> } = {
retries: 3,
headers: { "x-app": "web" },
};
function buildRequest(requestId: string) {
const cfg = { ...DEFAULTS }; // shallow: cfg.headers === DEFAULTS.headers
cfg.headers["x-request-id"] = requestId; // every later request now carries this id
return cfg;
}
// Fix: copy the level you change, or deep-clone plain data.
const cfg = { ...DEFAULTS, headers: { ...DEFAULTS.headers, "x-request-id": requestId } };
const copy = structuredClone(DEFAULTS);
const newest = orders.toSorted((a, b) => b.createdAt - a.createdAt); // orders untouchedCLOSE THE AI. EXPLAIN THIS.
Which built-in copy operations are shallow, and what does structuredClone deliberately not copy?HOW IT WORKS UNDERNEATH
RELATED SYMPTOMS
SOURCES
Guide reviewed