Create immutable state by mutating the current one with structural sharing
npx @tessl/cli install tessl/npm-immer@10.0.00
# Immer
1
2
Immer is a comprehensive immutable state management library that allows developers to create the next immutable state by simply mutating the current state tree. It provides a powerful produce function that works with structural sharing to efficiently create new immutable data structures while maintaining the familiar mutative JavaScript syntax.
3
4
## Package Information
5
6
- **Package Name**: immer
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install immer`
10
11
## Core Imports
12
13
```typescript
14
import { produce, Draft, Immutable, enablePatches } from "immer";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { produce, enablePatches } = require("immer");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { produce } from "immer";
27
28
// Basic state mutation
29
const baseState = {
30
todos: [
31
{ id: 1, text: "Learn Immer", done: false },
32
{ id: 2, text: "Use Immer in project", done: false }
33
],
34
user: { name: "John", age: 30 }
35
};
36
37
// Create new state by "mutating" a draft
38
const nextState = produce(baseState, draft => {
39
draft.todos[0].done = true;
40
draft.user.age = 31;
41
draft.todos.push({ id: 3, text: "Master Immer", done: false });
42
});
43
44
// baseState is unchanged, nextState contains the updates
45
console.log(baseState === nextState); // false
46
console.log(baseState.todos === nextState.todos); // false (structural sharing)
47
```
48
49
## Architecture
50
51
Immer is built around several key components:
52
53
- **Proxy System**: Creates draft proxies that track mutations without affecting the original data
54
- **Structural Sharing**: Efficiently reuses unchanged parts of the state tree in the new immutable state
55
- **Producer Functions**: Recipe functions that describe how to transform state using familiar mutation syntax
56
- **Type Safety**: Full TypeScript support with `Draft<T>` and `Immutable<T>` utility types
57
- **Plugin Architecture**: Optional plugins for patches tracking and Map/Set support
58
- **Zero Dependencies**: Self-contained with no external runtime dependencies
59
60
## Capabilities
61
62
### Core Production
63
64
The main `produce` function and related production utilities for creating immutable state through mutation-like syntax.
65
66
```typescript { .api }
67
function produce<T>(
68
base: T,
69
recipe: (draft: Draft<T>) => void | T | undefined
70
): T;
71
72
function produce<T>(
73
recipe: (draft: Draft<T>) => void | T | undefined
74
): (base: T) => T;
75
76
function produceWithPatches<T>(
77
base: T,
78
recipe: (draft: Draft<T>) => void | T | undefined
79
): [T, Patch[], Patch[]];
80
```
81
82
[Core Production](./core-production.md)
83
84
### Draft Management
85
86
Direct draft creation and manipulation utilities for advanced use cases and fine-grained control over the immutable update process.
87
88
```typescript { .api }
89
function createDraft<T extends Objectish>(base: T): Draft<T>;
90
91
function finishDraft<D extends Draft<any>>(
92
draft: D,
93
patchListener?: PatchListener
94
): D extends Draft<infer T> ? T : never;
95
96
function current<T>(value: T): T;
97
98
function original<T>(value: T): T | undefined;
99
```
100
101
[Draft Management](./draft-management.md)
102
103
### Patches System
104
105
Advanced patch tracking system for implementing undo/redo, debugging, and state synchronization features.
106
107
```typescript { .api }
108
function applyPatches<T>(base: T, patches: readonly Patch[]): T;
109
110
function enablePatches(): void;
111
112
interface Patch {
113
op: "replace" | "remove" | "add";
114
path: (string | number)[];
115
value?: any;
116
}
117
```
118
119
[Patches System](./patches-system.md)
120
121
### Configuration & Utilities
122
123
Configuration options and utility functions for customizing Immer behavior and working with types.
124
125
```typescript { .api }
126
function setAutoFreeze(value: boolean): void;
127
128
function setUseStrictShallowCopy(value: boolean | "class_only"): void;
129
130
function freeze<T>(obj: T, deep?: boolean): T;
131
132
function isDraft(value: any): boolean;
133
134
function isDraftable(value: any): boolean;
135
136
function castDraft<T>(value: T): Draft<T>;
137
138
function castImmutable<T>(value: T): Immutable<T>;
139
```
140
141
[Configuration & Utilities](./configuration-utilities.md)
142
143
### Map & Set Support
144
145
Plugin that enables Immer to work with Map and Set objects, providing draft versions that track mutations.
146
147
```typescript { .api }
148
function enableMapSet(): void;
149
```
150
151
Enables drafting of Map and Set instances with full mutation tracking and structural sharing support.
152
153
**Usage Examples:**
154
155
```typescript
156
import { produce, enableMapSet } from "immer";
157
158
// Enable Map/Set support
159
enableMapSet();
160
161
// Working with Maps
162
const stateWithMap = {
163
userMap: new Map([
164
["user1", { name: "Alice", age: 30 }],
165
["user2", { name: "Bob", age: 25 }]
166
])
167
};
168
169
const updatedState = produce(stateWithMap, draft => {
170
// Map methods work normally in drafts
171
draft.userMap.set("user3", { name: "Charlie", age: 35 });
172
draft.userMap.get("user1")!.age = 31;
173
draft.userMap.delete("user2");
174
});
175
176
// Working with Sets
177
const stateWithSet = {
178
tags: new Set(["javascript", "react", "typescript"])
179
};
180
181
const updatedSet = produce(stateWithSet, draft => {
182
draft.tags.add("immer");
183
draft.tags.delete("react");
184
});
185
```
186
187
## Core Types
188
189
```typescript { .api }
190
type Draft<T> = T extends PrimitiveType
191
? T
192
: T extends AtomicObject
193
? T
194
: T extends ReadonlyMap<infer K, infer V>
195
? Map<Draft<K>, Draft<V>>
196
: T extends ReadonlySet<infer V>
197
? Set<Draft<V>>
198
: T extends WeakReferences
199
? T
200
: T extends object
201
? WritableDraft<T>
202
: T;
203
204
type PrimitiveType = number | string | boolean;
205
type AtomicObject = Function | Promise<any> | Date | RegExp;
206
207
type Immutable<T> = T extends PrimitiveType
208
? T
209
: T extends AtomicObject
210
? T
211
: T extends ReadonlyMap<infer K, infer V>
212
? ReadonlyMap<Immutable<K>, Immutable<V>>
213
: T extends ReadonlySet<infer V>
214
? ReadonlySet<Immutable<V>>
215
: T extends WeakReferences
216
? T
217
: T extends object
218
? { readonly [K in keyof T]: Immutable<T[K]> }
219
: T;
220
221
type WritableDraft<T> = {
222
-readonly [K in keyof T]: Draft<T[K]>;
223
};
224
225
type Producer<T> = (draft: Draft<T>) => T | void | undefined | (T extends undefined ? typeof NOTHING : never);
226
227
type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void;
228
229
type Objectish = object;
230
```
231
232
## Constants
233
234
```typescript { .api }
235
const nothing: unique symbol;
236
const immerable: unique symbol;
237
```
238
239
The `nothing` symbol is used in producer functions to indicate that a property should be deleted or set to `undefined`. When returned from a producer, it causes the entire state to become `undefined`.
240
241
The `immerable` symbol can be added to class prototypes to make them draftable by Immer. Classes marked with this symbol will be treated as plain objects during drafting.
242
243
## Immer Class
244
245
```typescript { .api }
246
class Immer {
247
constructor(config?: {
248
autoFreeze?: boolean;
249
useStrictShallowCopy?: boolean | "class_only";
250
});
251
252
produce: IProduce;
253
produceWithPatches: IProduceWithPatches;
254
createDraft<T extends Objectish>(base: T): Draft<T>;
255
finishDraft<D extends Draft<any>>(
256
draft: D,
257
patchListener?: PatchListener
258
): D extends Draft<infer T> ? T : never;
259
setAutoFreeze(value: boolean): void;
260
setUseStrictShallowCopy(value: boolean | "class_only"): void;
261
applyPatches<T extends Objectish>(base: T, patches: readonly Patch[]): T;
262
}
263
264
type StrictMode = boolean | "class_only";
265
type Objectish = object;
266
267
type ValidRecipeReturnType<State> =
268
| State
269
| void
270
| undefined
271
| (State extends undefined ? typeof NOTHING : never);
272
273
type WeakReferences = WeakMap<any, any> | WeakSet<any>;
274
```
275
276
Create custom Immer instances with specific configurations for different use cases.
277
278
### Advanced Usage
279
280
```typescript
281
import { produce, enablePatches, applyPatches, Immer } from "immer";
282
283
// Enable patches plugin for tracking changes
284
enablePatches();
285
286
// Use produceWithPatches to get change information
287
const [nextState, patches, inversePatches] = produceWithPatches(baseState, draft => {
288
draft.todos[0].done = true;
289
});
290
291
// Apply patches to recreate the same state change
292
const recreatedState = applyPatches(baseState, patches);
293
294
// Create isolated Immer instance with custom configuration
295
const immer = new Immer({
296
autoFreeze: false,
297
useStrictShallowCopy: "class_only"
298
});
299
300
const result = immer.produce(baseState, draft => {
301
draft.user.name = "Jane";
302
});
303
```