0
# Core Production
1
2
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.
3
4
## Capabilities
5
6
### produce
7
8
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.
9
10
```typescript { .api }
11
/**
12
* Creates immutable state by applying mutations to a draft of the base state
13
* @param base - The initial state to transform
14
* @param recipe - Function that receives a draft proxy for mutation
15
* @param patchListener - Optional listener for patch generation (requires enablePatches)
16
* @returns New immutable state or original state if no changes
17
*/
18
function produce<T>(
19
base: T,
20
recipe: (draft: Draft<T>) => void | T | undefined,
21
patchListener?: PatchListener
22
): T;
23
```
24
25
**Curried producer variant:**
26
27
```typescript { .api }
28
/**
29
* Creates a curried producer function
30
* @param recipe - Recipe function to apply to future base states
31
* @returns Function that accepts base state and returns transformed state
32
*/
33
function produce<T>(
34
recipe: (draft: Draft<T>) => void | T | undefined
35
): (base: T) => T;
36
```
37
38
**Curried producer with initial state:**
39
40
```typescript { .api }
41
/**
42
* Creates a curried producer with initial state
43
* @param recipe - Recipe function to apply
44
* @param initialState - Default state when none provided
45
* @returns Function that optionally accepts base state
46
*/
47
function produce<T>(
48
recipe: (draft: Draft<T>) => void | T | undefined,
49
initialState: T
50
): (base?: T) => T;
51
```
52
53
**Usage Examples:**
54
55
```typescript
56
import { produce } from "immer";
57
58
// Basic usage
59
const baseState = { count: 0, items: [1, 2, 3] };
60
61
const nextState = produce(baseState, draft => {
62
draft.count += 1;
63
draft.items.push(4);
64
});
65
66
// Curried producer
67
const increment = produce((draft: { count: number }) => {
68
draft.count += 1;
69
});
70
71
const result1 = increment({ count: 5 }); // { count: 6 }
72
const result2 = increment({ count: 10 }); // { count: 11 }
73
74
// Returning a value from recipe (replaces entire state)
75
const replaced = produce(baseState, draft => {
76
return { count: 100, items: [10, 20] };
77
});
78
79
// Conditional updates
80
const conditionalUpdate = produce(baseState, draft => {
81
if (draft.count < 10) {
82
draft.count *= 2;
83
}
84
});
85
86
// Working with arrays
87
const todos = [
88
{ id: 1, text: "Learn Immer", done: false },
89
{ id: 2, text: "Use Immer", done: false }
90
];
91
92
const updatedTodos = produce(todos, draft => {
93
const todo = draft.find(t => t.id === 1);
94
if (todo) {
95
todo.done = true;
96
}
97
draft.push({ id: 3, text: "Master Immer", done: false });
98
});
99
```
100
101
### produceWithPatches
102
103
Like `produce`, but always returns a tuple containing the next state, patches describing the changes, and inverse patches for reverting the changes.
104
105
```typescript { .api }
106
/**
107
* Produces next state with patch information for change tracking
108
* @param base - The initial state to transform
109
* @param recipe - Function that receives a draft proxy for mutation
110
* @returns Tuple of [nextState, patches, inversePatches]
111
*/
112
function produceWithPatches<T>(
113
base: T,
114
recipe: (draft: Draft<T>) => void | T | undefined
115
): [T, Patch[], Patch[]];
116
```
117
118
**Requirements:** Must call `enablePatches()` before using this function.
119
120
**Usage Examples:**
121
122
```typescript
123
import { produceWithPatches, enablePatches, applyPatches } from "immer";
124
125
// Enable patches functionality
126
enablePatches();
127
128
const baseState = {
129
user: { name: "John", age: 30 },
130
todos: ["Learn Immer"]
131
};
132
133
const [nextState, patches, inversePatches] = produceWithPatches(baseState, draft => {
134
draft.user.age = 31;
135
draft.todos.push("Use Immer in project");
136
});
137
138
console.log(patches);
139
// [
140
// { op: "replace", path: ["user", "age"], value: 31 },
141
// { op: "add", path: ["todos", 1], value: "Use Immer in project" }
142
// ]
143
144
console.log(inversePatches);
145
// [
146
// { op: "replace", path: ["user", "age"], value: 30 },
147
// { op: "remove", path: ["todos", 1] }
148
// ]
149
150
// Apply patches to recreate the change
151
const recreated = applyPatches(baseState, patches);
152
console.log(recreated === nextState); // false (different objects)
153
console.log(JSON.stringify(recreated) === JSON.stringify(nextState)); // true (same content)
154
155
// Revert changes using inverse patches
156
const reverted = applyPatches(nextState, inversePatches);
157
console.log(JSON.stringify(reverted) === JSON.stringify(baseState)); // true
158
```
159
160
### Return Value Semantics
161
162
Producer functions support several return patterns:
163
164
```typescript
165
import { produce, nothing } from "immer";
166
167
const state = { items: [1, 2, 3], meta: { count: 3 } };
168
169
// Return undefined (default) - apply draft mutations
170
const result1 = produce(state, draft => {
171
draft.items.push(4);
172
draft.meta.count += 1;
173
// implicit return undefined
174
});
175
176
// Return the draft - apply draft mutations
177
const result2 = produce(state, draft => {
178
draft.items.push(5);
179
return draft; // same as returning undefined
180
});
181
182
// Return a completely new object - replace entire state
183
const result3 = produce(state, draft => {
184
return { items: [10, 20], meta: { count: 2 } };
185
});
186
187
// Return nothing symbol - replace state with undefined
188
const result4 = produce(state, draft => {
189
return nothing;
190
}); // result4 is undefined
191
192
// Conditional replacement
193
const result5 = produce(state, draft => {
194
if (draft.items.length > 5) {
195
return { items: [], meta: { count: 0 } }; // reset
196
}
197
draft.items.push(6); // mutation
198
});
199
```
200
201
## Type Safety
202
203
```typescript { .api }
204
interface IProduce {
205
// Base + recipe + optional patchListener
206
<T = any>(
207
base: T,
208
recipe: (draft: Draft<T>) => void | T | undefined,
209
listener?: PatchListener
210
): T;
211
212
// Curried producer
213
<T = any>(
214
recipe: (draft: Draft<T>) => void | T | undefined
215
): (base: T) => T;
216
217
// Curried producer with initial state
218
<T = any>(
219
recipe: (draft: Draft<T>) => void | T | undefined,
220
initialState: T
221
): (base?: T) => T;
222
}
223
224
interface IProduceWithPatches {
225
<T = any>(
226
base: T,
227
recipe: (draft: Draft<T>) => void | T | undefined
228
): [T, Patch[], Patch[]];
229
}
230
```
231
232
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.