Immer's produce(base, recipe) lets you write the next immutable state by mutating a draft, a proxy over the old state, while the original stays untouched and every sub-tree you did not change is shared by reference. You call draft.x = 1, draft.list.push(item), or delete draft.y as if you were editing the state in place, and produce returns a brand-new state that reflects those edits. This is the engine behind Immer, the library that powers immutable updates in Redux Toolkit. See the Immer docs for the full API.
Build immerProduce, an object with a produce method (and a small isDraft helper).
type Recipe<T> = (draft: T) => void;
const immerProduce: {
// Run recipe against a draft of baseState, then return the next state.
// Sub-trees you did not change are kept by reference; if the recipe
// changed nothing, the original baseState is returned unchanged.
produce<T>(baseState: T, recipe: Recipe<T>): T;
// True only for a draft proxy handed to a recipe.
isDraft(value: unknown): boolean;
};
const base = { user: { name: 'Ada' }, tags: ['x'] };
const next = immerProduce.produce(base, (draft) => {
draft.user.name = 'Ada L.';
});
next.user.name; // 'Ada L.'
base.user.name; // 'Ada' (original untouched)
next.tags === base.tags; // true (unchanged branch shared)
next.user === base.user; // false (edited branch copied)
const base = { count: 0, list: [1, 2] };
immerProduce.produce(base, () => {}) === base; // true (nothing changed → same reference)
const next = immerProduce.produce(base, (draft) => {
draft.list.push(3);
});
next.list; // [1, 2, 3]
base.list; // [1, 2] (original array untouched)
baseState; reading a nested property returns a nested draft lazily, and writing marks that node and its ancestors as copied.===) in the result; only nodes on the edited path are shallow-copied.produce returns the original baseState object, not a copy.produce returns, baseState and all of its nested objects are exactly as they were.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.