CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-immer

Create immutable state by mutating the current one with structural sharing

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

core-production.mddocs/

Core Production

The core production capabilities of Immer, centered around the produce function and its variants. These functions provide the main interface for creating immutable state through mutation-like syntax.

Capabilities

produce

The main function that takes a value and a "recipe function" to create immutable updates. The recipe function can mutate its first argument (a draft) and all mutations are applied to a copy of the base state.

/**
 * Creates immutable state by applying mutations to a draft of the base state
 * @param base - The initial state to transform
 * @param recipe - Function that receives a draft proxy for mutation
 * @param patchListener - Optional listener for patch generation (requires enablePatches)
 * @returns New immutable state or original state if no changes
 */
function produce<T>(
  base: T,
  recipe: (draft: Draft<T>) => void | T | undefined,
  patchListener?: PatchListener
): T;

Curried producer variant:

/**
 * Creates a curried producer function
 * @param recipe - Recipe function to apply to future base states
 * @returns Function that accepts base state and returns transformed state
 */
function produce<T>(
  recipe: (draft: Draft<T>) => void | T | undefined
): (base: T) => T;

Curried producer with initial state:

/**
 * Creates a curried producer with initial state
 * @param recipe - Recipe function to apply
 * @param initialState - Default state when none provided
 * @returns Function that optionally accepts base state
 */
function produce<T>(
  recipe: (draft: Draft<T>) => void | T | undefined,
  initialState: T
): (base?: T) => T;

Usage Examples:

import { produce } from "immer";

// Basic usage
const baseState = { count: 0, items: [1, 2, 3] };

const nextState = produce(baseState, draft => {
  draft.count += 1;
  draft.items.push(4);
});

// Curried producer
const increment = produce((draft: { count: number }) => {
  draft.count += 1;
});

const result1 = increment({ count: 5 }); // { count: 6 }
const result2 = increment({ count: 10 }); // { count: 11 }

// Returning a value from recipe (replaces entire state)
const replaced = produce(baseState, draft => {
  return { count: 100, items: [10, 20] };
});

// Conditional updates
const conditionalUpdate = produce(baseState, draft => {
  if (draft.count < 10) {
    draft.count *= 2;
  }
});

// Working with arrays
const todos = [
  { id: 1, text: "Learn Immer", done: false },
  { id: 2, text: "Use Immer", done: false }
];

const updatedTodos = produce(todos, draft => {
  const todo = draft.find(t => t.id === 1);
  if (todo) {
    todo.done = true;
  }
  draft.push({ id: 3, text: "Master Immer", done: false });
});

produceWithPatches

Like produce, but always returns a tuple containing the next state, patches describing the changes, and inverse patches for reverting the changes.

/**
 * Produces next state with patch information for change tracking
 * @param base - The initial state to transform
 * @param recipe - Function that receives a draft proxy for mutation
 * @returns Tuple of [nextState, patches, inversePatches]
 */
function produceWithPatches<T>(
  base: T,
  recipe: (draft: Draft<T>) => void | T | undefined
): [T, Patch[], Patch[]];

Requirements: Must call enablePatches() before using this function.

Usage Examples:

import { produceWithPatches, enablePatches, applyPatches } from "immer";

// Enable patches functionality
enablePatches();

const baseState = {
  user: { name: "John", age: 30 },
  todos: ["Learn Immer"]
};

const [nextState, patches, inversePatches] = produceWithPatches(baseState, draft => {
  draft.user.age = 31;
  draft.todos.push("Use Immer in project");
});

console.log(patches);
// [
//   { op: "replace", path: ["user", "age"], value: 31 },
//   { op: "add", path: ["todos", 1], value: "Use Immer in project" }
// ]

console.log(inversePatches);
// [
//   { op: "replace", path: ["user", "age"], value: 30 },
//   { op: "remove", path: ["todos", 1] }
// ]

// Apply patches to recreate the change
const recreated = applyPatches(baseState, patches);
console.log(recreated === nextState); // false (different objects)
console.log(JSON.stringify(recreated) === JSON.stringify(nextState)); // true (same content)

// Revert changes using inverse patches
const reverted = applyPatches(nextState, inversePatches);
console.log(JSON.stringify(reverted) === JSON.stringify(baseState)); // true

Return Value Semantics

Producer functions support several return patterns:

import { produce, nothing } from "immer";

const state = { items: [1, 2, 3], meta: { count: 3 } };

// Return undefined (default) - apply draft mutations
const result1 = produce(state, draft => {
  draft.items.push(4);
  draft.meta.count += 1;
  // implicit return undefined
});

// Return the draft - apply draft mutations
const result2 = produce(state, draft => {
  draft.items.push(5);
  return draft; // same as returning undefined
});

// Return a completely new object - replace entire state
const result3 = produce(state, draft => {
  return { items: [10, 20], meta: { count: 2 } };
});

// Return nothing symbol - replace state with undefined
const result4 = produce(state, draft => {
  return nothing;
}); // result4 is undefined

// Conditional replacement
const result5 = produce(state, draft => {
  if (draft.items.length > 5) {
    return { items: [], meta: { count: 0 } }; // reset
  }
  draft.items.push(6); // mutation
});

Type Safety

interface IProduce {
  // Base + recipe + optional patchListener
  <T = any>(
    base: T,
    recipe: (draft: Draft<T>) => void | T | undefined,
    listener?: PatchListener
  ): T;
  
  // Curried producer
  <T = any>(
    recipe: (draft: Draft<T>) => void | T | undefined
  ): (base: T) => T;
  
  // Curried producer with initial state
  <T = any>(
    recipe: (draft: Draft<T>) => void | T | undefined,
    initialState: T
  ): (base?: T) => T;
}

interface IProduceWithPatches {
  <T = any>(
    base: T,
    recipe: (draft: Draft<T>) => void | T | undefined
  ): [T, Patch[], Patch[]];
}

The core production functions provide the foundation for all immutable state updates in Immer, with full TypeScript support and flexible usage patterns for different scenarios.

docs

configuration-utilities.md

core-production.md

draft-management.md

index.md

patches-system.md

tile.json