or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-utilities.mdcore-production.mddraft-management.mdindex.mdpatches-system.md
tile.json

index.mddocs/

0

# 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

```