पाठ 5 / 25

Copying versus Structural Sharing

Spread, persistent data structures and Immer.

Shallow copies and shared structure

The spread syntax ({...obj}, [...arr]) makes a shallow copy: top-level properties are copied, nested objects are still shared by reference. For a nested update you copy each level along the path and reuse everything else; this is structural sharing, and it is safe precisely because nothing is mutated. Persistent data structures (for example the tries used by Clojure, Scala and libraries such as Immutable.js) do this automatically and make updates to large collections cheap. Immer lets you write code that looks like mutation on a draft and produces a new immutable value with structural sharing.

Nested update by hand and with Immer

Only the changed path is copied.

type State = {
  user: { name: string; address: { city: string; zip: string } };
  cart: string[];
};

// By hand: copy each level along the path
function moveTo(state: State, city: string): State {
  return {
    ...state,
    user: {
      ...state.user,
      address: { ...state.user.address, city },
    },
  };
  // state.cart is reused (shared), not copied
}

// With Immer (npm package "immer"): write against a draft
import { produce } from 'immer';
const moveTo2 = (state: State, city: string) =>
  produce(state, draft => {
    draft.user.address.city = city;
  });

structuredClone is not structural sharing

structuredClone makes a deep copy of everything, which is safe but allocates the whole tree. Prefer path copying or Immer for state updates.

त्वरित जाँच: After `const b = { ...a }`, what is true of a nested object `a.inner`?

  • `b.inner` is a deep copy
  • `b.inner` is the same object as `a.inner`
  • `b.inner` is undefined
  • `a.inner` is frozen
Answer

`b.inner` is the same object as `a.inner` — Spread copies only one level.