# Technical Documentation: immerjs/immer

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/immerjs/immer)

### Overview (`readme.md`)

<img src="images/immer-logo.svg" height="200px" align="right"/>

# Immer

[](https://www.npmjs.com/package/immer) [](https://github.com/immerjs/immer/actions?query=branch%3Amain) [](https://coveralls.io/github/immerjs/immer?branch=main) [](https://github.com/prettier/prettier) [](#backers) [](#sponsors) [](https://gitpod.io/#https://github.com/immerjs/immer)

_Create the next immutable state tree by simply modifying the current tree_

Winner of the "Breakthrough of the year" [React open source award](https://osawards.com/react/) and "Most impactful contribution" [JavaScript open source award](https://osawards.com/javascript/) in 2019

## Contribute using one-click online setup

You can use Gitpod (a free online VSCode like IDE) for contributing online. With a single click it will launch a workspace and automatically:

- clone the immer repo.
- install the dependencies.
- run `yarn run start`.

so that you can start coding straight away.

[](https://gitpod.io/from-referrer/)

## Documentation

The documentation of this package is hosted at https://immerjs.github.io/immer/

## Support

Did Immer make a difference to your project? Join the open collective at https://opencollective.com/immer!

## Release notes

https://github.com/immerjs/immer/releases

---

### Overview (`perf-testing/README.md`)

# Immer Performance Testing

This directory contains performance testing tools for Immer, allowing you to benchmark different versions of Immer and analyze CPU profiles to identify performance bottlenecks.

## Setup

1. **Install dependencies** (in this directory):

   ```bash
   yarn install
   ```

2. **Build Immer first**:

   ```bash
   yarn build-immer
   ```

3. **Build the benchmark bundle**:
   ```bash
   yarn build
   ```

Alternately, you can rebuild both Immer and the benchmarking script:

```bash
yarn build-with-latest
```

## Usage

### Running Benchmarks

To run the performance benchmarks:

```bash
# Run basic benchmarks, with relative version speed comparisons
yarn benchmark

# Run the benchmarks, but also generate a CPU profile
yarn profile
```

### Analyzing CPU Profiles

After running `yarn profile`, you'll get a `.cpuprofile` file. To analyze it:

```bash
# Analyze the most recent profile
yarn analyze-profile your-profile.cpuprofile
```

## What's Included

- **immutability-benchmarks.mjs**: Main benchmark script comparing different Immer versions
- **read-cpuprofile.js**: Advanced CPU profile analyzer with sourcemap support
- **rolldown.config.js**: Bundler configuration that eliminates `process.env` overhead

## Benchmark Versions

The benchmarks compare:

- **immer7-10**: Historical Immer versions
- **immer10Perf**: Current development version (references `../dist`)
- **vanilla**: Pure JavaScript implementations for baseline comparison

## Key Features

- **Sourcemap support**: CPU profile analysis includes original function names
- **Version-aware analysis**: Breaks down performance by Immer version
- **Production bundling**: Uses Rolldown to eliminate development overhead

---

### Api (`website/docs/api.md`)

---
id: api
title: API overview
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

| Exported name | Description | Section |
| --- | --- | --- |
| `produce` | The core API of Immer: `import {produce} from "immer"` | [Produce](./produce.mdx) |
| `applyPatches` | Given a base state or draft, and a set of patches, applies the patches | [Patches](./patches.mdx) |
| `castDraft` | Converts any immutable type to its mutable counterpart. This is just a cast and doesn't actually do anything. | [TypeScript](./typescript.mdx) |
| `castImmutable` | Converts any mutable type to its immutable counterpart. This is just a cast and doesn't actually do anything. | [TypeScript](./typescript.mdx) |
| `createDraft` | Given a base state, creates a mutable draft for which any modifications will be recorded | [Async](./async.mdx) |
| `current` | Given a draft object (doesn't have to be a tree root), takes a snapshot of the current state of the draft | [Current](./current.md) |
| `Draft<T>` | Exposed TypeScript type to convert an immutable type to a mutable type | [TypeScript](./typescript.mdx) |
| `enableArrayMethods()` | Enables optimized array method handling for improved performance with array-heavy operations. | [Array Methods](./array-methods.md) |
| `enableMapSet()` | Enables support for `Map` and `Set` collections. | [Installation](./installation.mdx#pick-your-immer-version) |
| `enablePatches()` | Enables support for JSON patches. | [Installation](./installation#pick-your-immer-version) |
| `finishDraft` | Given an draft created using `createDraft`, seals the draft and produces and returns the next immutable state that captures all the changes | [Async](./async.mdx) |
| `freeze(obj, deep?)` | Freezes draftable objects. Returns the original object. By default freezes shallowly, but if the second argument is `true` it will freeze recursively. |
| `Immer` | constructor that can be used to create a second "immer" instance (exposing all APIs listed in this instance), that doesn't share its settings with global instance. |
| `immerable` | Symbol that can be added to a constructor or prototype, to indicate that Immer should treat the class as something that can be safely drafted | [Classes](./complex-objects.md) |
| `Immutable<T>` | Exposed TypeScript type to convert mutable types to immutable types |  |
| `isDraft` | Returns true if the given object is a draft object |  |
| `isDraftable` | Returns true if Immer is capable of turning this object into a draft. Which is true for: arrays, objects without prototype, objects with `Object` as their prototype, objects that have the `immerable` symbol on their constructor or prototype |  |
| `nothing` | Value that can be returned from a recipe, to indicate that the value `undefined` should be produced | [Return](./return.mdx) |
| `original` | Given a draft object (doesn't have to be a tree root), returns the original object at the same path in the original state tree, if present | [Original](./original.md) |
| `Patch` | Exposed TypeScript type, describes the shape of an (inverse) patch object | [Patches](./patches.mdx) |
| `produceWithPatches` | Works the same as `produce`, but instead of just returning the produced object, it returns a tuple, consisting of `[result, patches, inversePatches]`. | [Patches](./patches.mdx) |
| `setAutoFreeze` | Enables / disables automatic freezing of the trees produces. By default enabled. | [Freezing](./freezing.mdx) |
| `setUseStrictShallowCopy` | Can be used to enable strict shallow copy. If enable, immer copies non-enumerable properties as much as possible. | [Classes](./complex-objects.md) |
| `setUseStrictIteration` | Controls iteration behavior: pass `false` for loose iteration (enumerable properties only, better performance) or `true` for strict iteration (includes symbols and non-enumerable properties). By default disabled (loose iteration). |  |

## Importing immer

In most cases, the only thing you need to import from Immer is `produce`:

```javascript
import {produce} from "immer"
```

Note that in older versions, `produce` was also available as default export (e.g. `import produce from "immer"` was also valid, but that is no longer the case to improve eco system compatibility.

---

### Array Methods (`website/docs/array-methods.md`)

---
id: array-methods
title: Array Methods Plugin
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

## Overview

The Array Methods Plugin (`enableArrayMethods()`) optimizes array operations within Immer producers by avoiding unnecessary Proxy creation during iteration. This provides significant performance improvements for array-heavy operations.

**Why does this matter?** Without the plugin, every array element access during iteration (e.g., in `filter`, `find`, `slice`) creates a Proxy object. For a 1000-element array, this means 1000+ proxy trap invocations just to iterate. With the plugin enabled, callbacks receive base (non-proxied) values, and proxies are only created as needed for mutation tracking.

## Installation

Enable the plugin once at your application's entry point:

```javascript
import {enableArrayMethods} from "immer"

enableArrayMethods()
```

This adds approximately **2KB** to your bundle size.

## Mutating Methods

These methods modify the array in-place and operate directly on the draft's internal copy without creating per-element proxies:

| Method      | Returns          | Description                           |
| ----------- | ---------------- | ------------------------------------- |
| `push()`    | New length       | Adds elements to the end              |
| `pop()`     | Removed element  | Removes and returns the last element  |
| `shift()`   | Removed element  | Removes and returns the first element |
| `unshift()` | New length       | Adds elements to the beginning        |
| `splice()`  | Removed elements | Adds/removes elements at any position |
| `sort()`    | The draft array  | Sorts elements in place               |
| `reverse()` | The draft array  | Reverses the array in place           |

```javascript
import {produce, enableArrayMethods} from "immer"

enableArrayMethods()

const base = {items: [3, 1, 4, 1, 5]}

const result = produce(base, draft => {
	draft.items.push(9) // Adds 9 to end
	draft.items.sort() // Sorts: [1, 1, 3, 4, 5, 9]
	draft.items.reverse() // Reverses: [9, 5, 4, 3, 1, 1]
})
```

## Non-Mutating Methods

Non-mutating methods are categorized based on what they return:

### Subset Operations (Return Drafts)

These methods select items that exist in the original array and **create draft proxies** for the returned items. The callbacks receive **base values** (the optimization), but the **returned array** contains newly created draft proxies that point back to the original positions. **Mutations to returned items WILL affect the draft state.**

| Method       | Returns                            | Drafts? |
| ------------ | ---------------------------------- | ------- |
| `filter()`   | Array of matching items            | ✅ Yes  |
| `slice()`    | Array of items in range            | ✅ Yes  |
| `find()`     | First matching item or `undefined` | ✅ Yes  |
| `findLast()` | Last matching item or `undefined`  | ✅ Yes  |

```javascript
const base = {
	items: [
		{id: 1, value: 10},
		{id: 2, value: 20},
		{id: 3, value: 30}
	]
}

const result = produce(base, draft => {
	// filter returns drafts - mutations track back to original
	const filtered = draft.items.filter(item => item.value > 15)
	filtered[0].value = 999 // This WILL affect draft.items[1]

	// find returns a draft - mutations track back
	const found = draft.items.find(item => item.id === 3)
	if (found) {
		found.value = 888 // This WILL affect draft.items[2]
	}

	// slice returns drafts
	const sliced = draft.items.slice(0, 2)
	sliced[0].value = 777 // This WILL affect draft.items[0]
})

console.log(result.items[0].value) // 777
console.log(result.items[1].value) // 999
console.log(result.items[2].value) // 888
```

### Transform Operations (Return Base Values)

These methods create **new arrays** that may include external items or restructured data. They return **base values**, NOT drafts. **Mutations to returned items will NOT track back to the draft state.**

| Method     | Returns             | Drafts? |
| ---------- | ------------------- | ------- |
| `concat()` | New combined array  | ❌ No   |
| `flat()`   | New flattened array | ❌ No   |

```javascript
const base = {items: [{id: 1, value: 10}]}

const result = produce(base, draft => {
	// concat returns base values - mutations DON'T track
	const concatenated = draft.items.concat([{id: 2, value: 20}])
	concatenated[0].value = 999 // This will NOT affect draft.items[0]

	// To actually use concat results, assign them:
	draft.items = draft.items.concat([{id: 2, value: 20}])
})

// Original unchanged because concat result wasn't assigned
console.log(result.items[0].value) // 10 (unchanged)
```

**Why the distinction?**

- **Subset operations** (`filter`, `slice`, `find`) select items that exist in the original array. Returning drafts allows mutations to propagate back to the source.
- **Transform operations** (`concat`, `flat`) create new data structures that may include external items or restructured data, making draft tracking impractical.

### Primitive-Returning Methods

These methods return primitive values (numbers, booleans, strings). No tracking issues since primitives aren't draftable:

| Method             | Returns              |
| ------------------ | -------------------- |
| `indexOf()`        | Number (index or -1) |
| `lastIndexOf()`    | Number (index or -1) |
| `includes()`       | Boolean              |
| `some()`           | Boolean              |
| `every()`          | Boolean              |
| `findIndex()`      | Number (index or -1) |
| `findLastIndex()`  | Number (index or -1) |
| `join()`           | String               |
| `toString()`       | String               |
| `toLocaleString()` | String               |

```javascript
const base = {
	items: [
		{id: 1, active: true},
		{id: 2, active: false}
	]
}

const result = produce(base, draft => {
	const index = draft.items.findIndex(item => item.id === 2)
	const hasActive = draft.items.some(item => item.active)
	const allActive = draft.items.every(item => item.active)

	console.log(index) // 1
	console.log(hasActive) // true
	console.log(allActive) // false
})
```

## Methods NOT Overridden

The following methods are **not** intercepted by the plugin and work through standard Proxy behavior. Callbacks receive drafts, and mutations track normally:

| Method          | Description                       |
| --------------- | --------------------------------- |
| `map()`         | Transform each element            |
| `flatMap()`     | Map then flatten                  |
| `forEach()`     | Execute callback for each element |
| `reduce()`      | Reduce to single value            |
| `reduceRight()` | Reduce from right to left         |

```javascript
const base = {
	items: [
		{id: 1, value: 10, nested: {count: 0}},
		{id: 2, value: 20, nested: {count: 0}}
	]
}

const result = produce(base, draft => {
	// forEach receives drafts - mutations work normally
	draft.items.forEach(item => {
		item.value *= 2
	})

	// map is NOT overridden - callbacks receive drafts
	// The returned array items are also drafts (extracted from draft.items)
	const mapped = draft.items.map(item => item.nested)
	// Mutations to the result array propagate back
	mapped[0].count = 999 // ✅ This affects draft.items[0].nested.count
})

console.log(result.items[0].nested.count) // 999
```

## Callback Behavior

For overridden methods, callbacks receive **base values** (not drafts). This is the core optimization - it avoids creating proxies for every element during iteration.

```javascript
const base = {
	items: [
		{id: 1, value: 10},
		{id: 2, value: 20}
	]
}

produce(base, draft => {
	draft.items.filter(item => {
		// `item` is a base value here, NOT a draft
		// Reading properties works fine
		return item.value > 15

		// But direct mutation here won't be tracked:
		// item.value = 999  // ❌ Won't affect draft
	})

	// Instead, use the returned draft:
	const filtered = draft.items.filter(item => item.value > 15)
	filtered[0].value = 999 // ✅ This works because filtered[0] is a draft
})
```

## Method Return Behavior Summary

| Category | Methods | Returns | Mutations Track? |
| --- | --- | --- | --- |
| **Subset** | `filter`, `slice`, `find`, `findLast` | Draft proxies | ✅ Yes |
| **Transform** | `concat`, `flat` | Base values | ❌ No |
| **Primitive** | `indexOf`, `includes`, `some`, `every`, `findIndex`, `findLastIndex`, `lastIndexOf`, `join`, `toString`, `toLocaleString` | Primitives | N/A |
| **Mutating** | `push`, `pop`, `shift`, `unshift`, `splice`, `sort`, `reverse` | Various | ✅ Yes (modifies draft) |
| **Not Overridden** | `map`, `flatMap`, `forEach`, `reduce`, `reduceRight` | Standard behavior | ✅ Yes (callbacks get drafts) |

## When to Use

Enable the Array Methods Plugin when:

- Your application has significant array iteration within producers
- You frequently use methods like `filter`, `find`, `some`, `every` on large arrays
- Performance profiling shows array operations as a bottleneck

The plugin is most beneficial for:

- Large arrays (100+ elements)
- Frequent producer calls with array operations
- Read-heavy operations (filtering, searching) where most elements aren't modified

## Performance Benefit

**Without the plugin:**

- Every array element access during iteration creates a Proxy
- A `filter()` on 1000 elements = 1000+ proxy creations

**With the plugin:**

- Callbacks receive base values directly
- Proxies only created for the specific elements you actually mutate, or that match filtering predicates

```javascript
// Without plugin: ~3000+ proxy trap invocations
// With plugin: ~10-20 proxy trap invocations
const result = produce(largeState, draft => {
	const filtered = draft.items.filter(x => x.value > threshold)
	// Only items you mutate get proxied
	filtered.forEach(item => {
		item.processed = true
	})
})
```

---

### Async (`website/docs/async.mdx`)

---
id: async
title: createDraft / finishDraft
sidebar_label: createDraft / finishDraft
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 11: Creating <b>async</b> producers (and why you
		shouldn’t)
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t"
	>
		Hosted on egghead.io
	</a>
</details>

## `createDraft` and `finishDraft`

`createDraft` and `finishDraft` are two low-level functions that are mostly useful for libraries that build abstractions on top of immer. It avoids the need to always create a function in order to work with drafts. Instead, one can create a draft, modify it, and at some time in the future finish the draft, in which case the next immutable state will be produced.

Beyond that, `createDraft` / `finishDraft` could be used to express async updates to drafts:

```javascript
import {createDraft, finishDraft} from "immer"

const user = {
	name: "michel",
	todos: []
}

const draft = createDraft(user)
draft.todos = await (await window.fetch("http://host/" + draft.name)).json()
const loadedUser = finishDraft(draft)
```

Note: The above is an anti-pattern! First fetch data instead, then draft the `user`. Otherwise updates to user that happen during the async process, would be "missed" by the draft.

Note: `finishDraft` takes a `patchListener` as second argument, which can be used to record the patches, similarly to `produce`.

_Warning: in general, we recommend to use `produce` instead of the `createDraft` / `finishDraft` combo, `produce` is less error prone in usage, and more clearly separates the concepts of mutability and immutability in your code base._

---

### Built With (`website/docs/built-with.md`)

---
id: built-with
title: Built with Immer
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

- [react-copy-write](https://github.com/aweary/react-copy-write) _Immutable state with a mutable API_
- [redux-toolkit](https://github.com/reduxjs/redux-toolkit) _The official, opinionated, batteries-included toolset for efficient Redux development_
- [immer based handleActions](https://gist.github.com/kitze/fb65f527803a93fb2803ce79a792fff8) _Boilerplate free actions for Redux_
- [redux-box](https://github.com/anish000kumar/redux-box) _Modular and easy-to-grasp redux based state management, with least boilerplate_
- [quick-redux](https://github.com/jeffreyyoung/quick-redux) _tools to make redux development quicker and easier_
- [bey](https://github.com/jamiebuilds/bey) _Simple immutable state for React using Immer_
- [cool-store](https://github.com/Maxvien/cool-store) _CoolStore is an immutable state store built on top of ImmerJS and RxJS_
- [immer-wieder](https://github.com/drcmda/immer-wieder#readme) _State management lib that combines React 16 Context and immer for Redux semantics_
- [robodux](https://github.com/neurosnap/robodux) _flexible way to reduce redux boilerplate_
- [immer-reducer](https://github.com/epeli/immer-reducer) _Type-safe and terse React (useReducer()) and Redux reducers with Typescript_
- [redux-ts-utils](https://github.com/knpwrs/redux-ts-utils) _Everything you need to create type-safe applications with Redux with a strong emphasis on simplicity_
- [react-state-tree](https://github.com/suchipi/react-state-tree) _Drop-in replacement for useState that persists your state into a redux-like state tree_
- [redux-immer](https://github.com/salvoravida/redux-immer) _is used to create an equivalent function of Redux combineReducers that works with `immer` state. Like `redux-immutable` but for `immer`_
- [ngrx-wieder](https://github.com/nilsmehlhorn/ngrx-wieder) _Lightweight yet configurable solution for implementing undo-redo in Angular apps on top of NgRx and Immer_
- [immer-yjs](https://github.com/sep2/immer-yjs) _Combine `immer` with CRDT library `y.js` for easy json data manipulation_
- [immerhin](https://github.com/webstudio-is/immerhin) Sync state with undo/redo
- [zenith](https://github.com/do-md/zenith) *Reactive React state management on Immer with MobX-style computed properties and patch-based undo/redo, powering DOMD.*
- [domd](https://github.com/do-md/domd) *High-performance macOS markdown editor built on Immer's structural sharing, with near-O(1) per-keystroke rendering on large documents.*
- ... and [many more](https://www.npmjs.com/browse/depended/immer)

---

### Complex Objects (`website/docs/complex-objects.md`)

---
id: complex-objects
title: Classes
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

Plain objects (objects without a prototype), arrays, `Map`s and `Set`s are always drafted by Immer. Every other object must use the `immerable` symbol to mark itself as compatible with Immer. When one of these objects is mutated within a producer, its prototype is preserved between copies.

```js
import {immerable} from "immer"

class Foo {
	[immerable] = true // Option 1

	constructor() {
		this[immerable] = true // Option 2
	}
}

Foo[immerable] = true // Option 3
```

### Example

```js
import {immerable, produce} from "immer"

class Clock {
	[immerable] = true

	constructor(hour, minute) {
		this.hour = hour
		this.minute = minute
	}

	get time() {
		return `${this.hour}:${this.minute}`
	}

	tick() {
		return produce(this, draft => {
			draft.minute++
		})
	}
}

const clock1 = new Clock(12, 10)
const clock2 = clock1.tick()
console.log(clock1.time) // 12:10
console.log(clock2.time) // 12:11
console.log(clock2 instanceof Clock) // true
```

### Semantics in detail

The semantics on how classes are drafted are as follows:

1. A draft of a class is a fresh object but with the same prototype as the original object.
1. When creating a draft, Immer will copy all _own_ properties from the base to the draft.This includes (in strict mode) non-enumerable and symbolic properties.
1. _Own_ getters will be invoked during the copy process, just like `Object.assign` would.
1. Inherited getters and methods will remain as is and be inherited by the draft, as they are stored on the prototype which is untouched.
1. Immer will not invoke constructor functions.
1. The final instance will be constructed with the same mechanism as the draft was created.
1. Only getters that have a setter as well will be writable in the draft, as otherwise the value can't be copied back.

Because Immer will dereference own getters of objects into normal properties, it is possible to use objects that use getter/setter traps on their fields, like MobX and Vue do.

Note that, by default, Immer does not strictly handle object's non-enumerable properties such as getters/setters for performance reason. If you want this behavior to be strict, you can opt-in with `useStrictShallowCopy(config)`. Use `true` to always copy strict, or `"class_only"` to only copy class instances strictly but use the faster loose copying for plain objects. The default is `false`. (Remember, regardless of strict mode, own getters / setters are always copied _by value_. There is currently no config to copy descriptors as-is. Feature request / PR welcome).

Immer does not support exotic / engine native objects such as DOM Nodes or Buffers, nor is subclassing Map, Set or arrays supported and the `immerable` symbol can't be used on them.

So when working for example with `Date` objects, you should always create a new `Date` instance instead of mutating an existing `Date` object.

---

### Current (`website/docs/current.md`)

---
id: current
title: Extracting the current state from a draft
sidebar_label: Current
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

Immer exposes a named export `current` that creates a copy of the current state of the draft. This can be very useful for debugging purposes (as those objects won't be Proxy objects and not be logged as such). Also, references to `current` can be safely leaked from a produce function. Put differently, `current` provides a snapshot of the current state of a draft.

Objects generated by `current` work similar to the objects created by produce itself.

1. Unmodified objects will be structurally shared with the original objects.
1. If no changes are made to a draft, generally it holds that `original(draft) === current(draft)`, but this is not guaranteed.
1. Future changes to the draft won't be reflected in the object produced by `current` (except for references to undraftable objects)
1. Unlike `produce` objects created by `current` will _not_ be frozen.

Use `current` sparingly, it can be a potentially expensive operation, especially when using ES5.

Note that `current` cannot be invoked on objects that aren't drafts.

### Example

The following example shows the effect of `current` (and `original`):

```js
const base = {
	x: 0
}

const next = produce(base, draft => {
	draft.x++
	const orig = original(draft)
	const copy = current(draft)
	console.log(orig.x)
	console.log(copy.x)

	setTimeout(() => {
		// this will execute after the produce has finished!
		console.log(orig.x)
		console.log(copy.x)
	}, 100)

	draft.x++
	console.log(draft.x)
})
console.log(next.x)

// This will print
// 0 (orig.x)
// 1 (copy.x)
// 2 (draft.x)
// 2 (next.x)
// 0 (after timeout, orig.x)
// 1 (after timeout, copy.x)
```

---

### Curried Produce (`website/docs/curried-produce.mdx`)

---
id: curried-produce
title: Curried producers
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 6: Simplify code by using curried _reduce_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/javascript-simplify-immer-producer-functions-using-currying/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/javascript-simplify-immer-producer-functions-using-currying"
	>
		Hosted on egghead.io
	</a>
</details>

Passing a function as the first argument to `produce` creates a function that doesn't apply `produce` yet to a specific state, but rather creates a function that will apply `produce` to any state that is passed to it in the future. This generally is called _currying_. Take for example the following example:

```javascript
import {produce} from "immer"

function toggleTodo(state, id) {
	return produce(state, draft => {
		const todo = draft.find(todo => todo.id === id)
		todo.done = !todo.done
	})
}

const baseState = [
	{
		id: "JavaScript",
		title: "Learn TypeScript",
		done: true
	},
	{
		id: "Immer",
		title: "Try Immer",
		done: false
	}
]

const nextState = toggleTodo(baseState, "Immer")
```

The above pattern of `toggleTodo` is quite typical; pass an existing state to `produce`, modify the `draft`, and then return the result. Since `state` isn't used for anything else than passing it on to `produce`, the above example can be simplified by using the _curried_ form of `produce`, where you pass `produce` only the recipe function, and `produce` will return a new function that will apply recipe to the base state. This allows us to shorten the above `toggleTodo` definition.

```javascript
import {produce} from "immer"

// curried producer:
const toggleTodo = produce((draft, id) => {
	const todo = draft.find(todo => todo.id === id)
	todo.done = !todo.done
})

const baseState = [
	/* as is */
]

const nextState = toggleTodo(baseState, "Immer")
```

Note that the `id` param has now become part of the recipe function! This pattern of having curried producers combines really neatly with for example the `useState` hook from React, as we will see on the next page.

---

### Example Setstate (`website/docs/example-setstate.mdx`)

---
id: example-setstate
title: React & Immer
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 8: Using Immer with _useState_. Or: _useImmer_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-immutable-update-state-inside-react-components-with-useimmer/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-immutable-update-state-inside-react-components-with-useimmer"
	>
		Hosted on egghead.io
	</a>
</details>

## useState + Immer

The `useState` hook assumes any state that is stored inside it is treated as immutable. Deep updates in the state of React components can be greatly simplified as by using Immer. The following example shows how to use `produce` in combination with `useState`, and can be tried on [CodeSandbox](https://codesandbox.io/s/immer-usestate-ujkgg?file=/src/index.js).

```javascript
import React, {useCallback, useState} from "react"
import {produce} from "immer"

const TodoList = () => {
	const [todos, setTodos] = useState([
		{
			id: "React",
			title: "Learn React",
			done: true
		},
		{
			id: "Immer",
			title: "Try Immer",
			done: false
		}
	])

	const handleToggle = useCallback(id => {
		setTodos(
			produce(draft => {
				const todo = draft.find(todo => todo.id === id)
				todo.done = !todo.done
			})
		)
	}, [])

	const handleAdd = useCallback(() => {
		setTodos(
			produce(draft => {
				draft.push({
					id: "todo_" + Math.random(),
					title: "A new todo",
					done: false
				})
			})
		)
	}, [])

	return <div>{/* See CodeSandbox */}</div>
}
```

## useImmer

Since all state updaters follow the same pattern where the update function is wrapped in `produce`, it is also possible to simplify the above by leveraging the [use-immer](https://www.npmjs.com/package/use-immer) package that will wrap updater functions in `produce` automatically:

```javascript
import React, { useCallback } from "react";
import { useImmer } from "use-immer";

const TodoList = () => {
  const [todos, setTodos] = useImmer([
    {
      id: "React",
      title: "Learn React",
      done: true
    },
    {
      id: "Immer",
      title: "Try Immer",
      done: false
    }
  ]);

  const handleToggle = useCallback((id) => {
    setTodos((draft) => {
      const todo = draft.find((todo) => todo.id === id);
      todo.done = !todo.done;
    });
  }, []);

  const handleAdd = useCallback(() => {
    setTodos((draft) => {
      draft.push({
        id: "todo_" + Math.random(),
        title: "A new todo",
        done: false
      });
    });
  }, []);

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          <label>
            <input
              type="checkbox"
              checked={todo.done}
              onChange={() => handleToggle(todo.id)}
            />
            {todo.title}
          </label>
        </li>
      ))}
      <button type="button" onClick={handleAdd}>
        Add todo
      </button>
    </ul>
  );
};
```

## useReducer + Immer

Similarly to `useState`, `useReducer` combines neatly with Immer as well, as demonstrated in this [CodeSandbox](https://codesandbox.io/s/immer-usereducer-bqpzn?file=/src/index.js:0-1018):

```javascript
import React, {useCallback, useReducer} from "react"
import {produce} from "immer"

const TodoList = () => {
	const [todos, dispatch] = useReducer(
		produce((draft, action) => {
			switch (action.type) {
				case "toggle":
					const todo = draft.find(todo => todo.id === action.id)
					todo.done = !todo.done
					break
				case "add":
					draft.push({
						id: action.id,
						title: "A new todo",
						done: false
					})
					break
				default:
					break
			}
		}),
		[
			/* initial todos */
		]
	)

	const handleToggle = useCallback(id => {
		dispatch({
			type: "toggle",
			id
		})
	}, [])

	const handleAdd = useCallback(() => {
		dispatch({
			type: "add",
			id: "todo_" + Math.random()
		})
	}, [])

	// etc
}
```

## useImmerReducer

...which again, can be slightly shorted by `useImmerReducer` from the `use-immer` package ([demo](https://codesandbox.io/s/useimmerreducer-sycpb?file=/src/index.js)):

```javascript
import React, { useCallback } from "react";
import { useImmerReducer } from "use-immer";

const TodoList = () => {
  const [todos, dispatch] = useImmerReducer(
    (draft, action) => {
      switch (action.type) {
        case "toggle":
          const todo = draft.find((todo) => todo.id === action.id);
          todo.done = !todo.done;
          break;
        case "add":
          draft.push({
            id: action.id,
            title: "A new todo",
            done: false
          });
          break;
        default:
          break;
      }
    },
    [ /* initial todos */ ]
  );

  //etc

```

## Redux + Immer

Redux + Immer is extensively covered in the documentation of [Redux Toolkit](https://redux-toolkit.js.org/usage/immer-reducers). For Redux without Redux Toolkit, the same trick as applied to `useReducer` above can be applied: wrap the reducer function with `produce`, and you can safely mutate the draft!

For example:

```javascript
import {produce} from "immer"

// Reducer with initial state
const INITIAL_STATE = [
	/* bunch of todos */
]

const todosReducer = produce((draft, action) => {
	switch (action.type) {
		case "toggle":
			const todo = draft.find(todo => todo.id === action.id)
			todo.done = !todo.done
			break
		case "add":
			draft.push({
				id: action.id,
				title: "A new todo",
				done: false
			})
			break
		default:
			break
	}
})
```

---

### Faq (`website/docs/faq.md`)

---
id: faq
title: Frequently Asked Questions
sidebar_label: FAQ
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

## Q: How does Immer work?

Read the (second part of the) [introduction blog](https://medium.com/@mweststrate/introducing-immer-immutability-the-easy-way-9d73d8f71cb3).

## Q: Does Immer use structural sharing? So that my selectors can be memoized and such?

A: Yes

## Q: Does Immer support deep updates?

A: Yes

## Q: I can't rely on Proxies being present on my target environments. Can I use Immer?

A: Yes - [view details](./installation.mdx#immer-on-older-javascript-environments)

## Q: Can I typecheck my data structures when using Immer?

A: Yes

## Q: Can I store `Date` objects, functions etc in my state tree when using Immer?

A: Yes

## Q: Can I use Maps and Sets?

A: Yes

## Q: Is it fast?

A: Yes

## Q: Idea! Can Immer freeze the state for me?

A: Yes

---

### Freezing (`website/docs/freezing.mdx`)

---
id: freezing
title: Auto freezing
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 7: Immer automatically freezes data
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/javascript-produces-immutable-data-and-avoid-unnecessary-creation-of-new-data-trees-with-immer/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/javascript-produces-immutable-data-and-avoid-unnecessary-creation-of-new-data-trees-with-immer"
	>
		Hosted on egghead.io
	</a>
</details>

Immer automatically freezes any state trees that are modified using `produce`. This protects against accidental modifications of the state tree outside of a producer. In most cases this provides the most optimal behavior, but `setAutoFreeze(true / false)` can be used to explicitly turn this feature on or off.

Immer will never freeze (the contents of) non-enumerable, non-own or symbolic properties, unless their content was drafted.

_⚠️ Immer freezes everything recursively, for large data objects that won't be changed in the future this might be over-kill, in that case it can be more efficient to shallowly pre-freeze data using the `freeze` utility.⚠️_

_⚠️ If auto freezing is enabled, recipes are not entirely side-effect free: Any plain object or array that ends up in the produced result, will be frozen, even when these objects were not frozen before the start of the producer! ⚠️_

---

### Installation (`website/docs/installation.mdx`)

---
id: installation
title: Installation
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>

Immer can be installed as a direct dependency, and will work in any ES5 environment:

- Yarn: `yarn add immer`
- NPM: `npm install immer`
- Deno: `deno install immer`
- CDN: Exposed global is `immer`
  - Unpkg: `<script src="https://unpkg.com/immer"></script>`
  - JSDelivr: `<script src="https://cdn.jsdelivr.net/npm/immer"></script>`
  - ⚠️ When using a CDN, it is best to check the url in your browser and see what version it resolves to, so that your users aren't accidentally served a newer version in the future when updates are release. So use a url like: https://unpkg.com/immer@6.0.3/dist/immer.umd.production.min.js instead. Substitute `production.min` with `development` in the URL for a development build.

## Pick your Immer version

_This section only applies to version 6 and later_

To make sure Immer is as small as possible, features that are not required by every project has been made opt-in, and have to be enabled explicitly. This ensures that when bundling your application for production, unused features don't take any space.

The following features can be opt-in to:

| Feature | Description | Method to call |
| --- | --- | --- |
| [Array Methods optimization](./array-methods.md) | Optimizes array method handling for improved performance with array-heavy operations | `enableArrayMethods()` |
| [ES2015 Map and Set support](./complex-objects.md) | To enable Immer to operate on the native `Map` and `Set` collections, enable this feature | `enableMapSet()` |
| [JSON Patch support](./patches.mdx) | Immer can keep track of all the changes you make to draft objects. This can be useful for communicating changes using JSON patches | `enablePatches()` |

For example, if you want to use `produce` on a `Map`, you need to enable this feature once during the start of your application:

```typescript
// In your application's entrypoint
import {enableMapSet} from "immer"

enableMapSet()

// ...later
import {produce} from "immer"

const usersById_v1 = new Map([
	["michel", {name: "Michel Weststrate", country: "NL"}]
])

const usersById_v2 = produce(usersById_v1, draft => {
	draft.get("michel").country = "UK"
})

expect(usersById_v1.get("michel").country).toBe("NL")
expect(usersById_v2.get("michel").country).toBe("UK")
```

Vanilla Immer kicks in at ~3KB gzipped. Every plugin that is enabled adds ~1-2 KB to that. The breakdown is as follows:

```
Import size report for immer:
┌───────────────────────┬───────────┬────────────┬───────────┐
│ (index)               │ just this │ cumulative │ increment │
├───────────────────────┼───────────┼────────────┼───────────┤
│ import * from 'immer' │ 6908      │ 0          │ 0         │
│ produce               │ 4183      │ 4183       │ 0         │
│ enableMapSet          │ 4971      │ 4980       │ 797       │
│ enablePatches         │ 5335      │ 6097       │ 1117      │
│ enableArrayMethods    │ 4768      │ 6659       │ 562       │
└───────────────────────┴───────────┴────────────┴───────────┘
(this report was generated by npmjs.com/package/import-size)
```

## Immer on older JavaScript environments?

By default `produce` tries to use proxies for optimal performance. However, on older JavaScript engines `Proxy` is not available. For example, when running Microsoft Internet Explorer or React Native (if < v0.59 or when using the Hermes engine on React Native < 0.64) on Android. In such cases, Immer will fallback to an ES5 compatible implementation which works identically, but is a bit slower.

- Since version 6, support for the fallback implementation has to be explicitly enabled by calling `enableES5()`.
- Version 10 drops the fallback implementation fully, and cannot be used in browsers / engines that don't support Proxy.

---

### Introduction (`website/docs/introduction.md`)

---
id: introduction
title: Introduction to Immer
sidebar_label: Introduction
slug: /
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

<img src="/immer/img/immer-logo.svg" style={{maxHeight:200}} align="right"/>

# Immer

Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.

> Immer is life-changing as a JS dev, and I'm not even exaggerating :) Like, it's right up there with Prettier in terms of "wow this package is amazing, how did I ever live without it?" --Mark Erikson, (the) Redux Maintainer, @replayio

Winner of the "Breakthrough of the year" [React open source award](https://osawards.com/react/) and "Most impactful contribution" [JavaScript open source award](https://osawards.com/javascript/) in 2019.

---

- Introduction blogpost: [Immer: Immutability the easy way](https://medium.com/@mweststrate/introducing-immer-immutability-the-easy-way-9d73d8f71cb3)
- Short Egghead.io lesson covering the Immer essentials: [Simplify creating immutable data trees with Immer (7m)](https://egghead.io/lessons/redux-simplify-creating-immutable-data-trees-with-immer)
- Free in-depth Egghead.io course: [Immutable JavaScript Data Structures with Immer (58m)](https://egghead.io/courses/immutable-javascript-data-structures-with-immer)

---

### Immer simplifies handling immutable data structures

Immer can be used in any context in which immutable data structures need to be used. For example in combination with React state, React or Redux reducers, or configuration management. Immutable data structures allow for (efficient) change detection: if the reference to an object didn't change, the object itself did not change. In addition, it makes cloning relatively cheap: Unchanged parts of a data tree don't need to be copied and are shared in memory with older versions of the same state.

Generally speaking, these benefits can be achieved by making sure you never change any property of an object, array or map, but by always creating an altered copy instead. In practice this can result in code that is quite cumbersome to write, and it is easy to accidentally violate those constraints. Immer will help you to follow the immutable data paradigm by addressing these pain points:

1. Immer will detect accidental mutations and throw an error.
2. Immer will remove the need for the typical boilerplate code that is needed when creating deep updates to immutable objects: Without Immer, object copies need to be made by hand at every level. Typically by using a lot of `...` spread operations. When using Immer, changes are made to a `draft` object, that records the changes and takes care of creating the necessary copies, without ever affecting the original object.
3. When using Immer, you don't need to learn dedicated APIs or data structures to benefit from the paradigm. With Immer you'll use plain JavaScript data structures, and use the well-known mutable JavaScript APIs, but safely.

### A quick example for comparison

```javascript
const baseState = [
	{
		title: "Learn TypeScript",
		done: true
	},
	{
		title: "Try Immer",
		done: false
	}
]
```

Imagine we have the above base state, and we'll need to update the second todo, and add a third one. However, we don't want to mutate the original `baseState`, and we want to avoid deep cloning as well (to preserve the first todo).

#### Without Immer

Without Immer, we'll have to carefully shallow copy every level of the state structure that is affected by our change:

```javascript
const nextState = baseState.slice() // shallow clone the array
nextState[1] = {
	// replace element 1...
	...nextState[1], // with a shallow clone of element 1
	done: true // ...combined with the desired update
}
// since nextState was freshly cloned, using push is safe here,
// but doing the same thing at any arbitrary time in the future would
// violate the immutability principles and introduce a bug!
nextState.push({title: "Tweet about it"})
```

#### With Immer

With Immer, this process is more straightforward. We can leverage the `produce` function, which takes as first argument the state we want to start from, and as second argument we pass a function, called the _recipe_, that is passed a `draft` to which we can apply straightforward mutations. Those mutations are recorded and used to produce the next state once the recipe is done. `produce` will take care of all the necessary copying, and protect against future accidental modifications as well by freezing the data.

```javascript
import {produce} from "immer"

const nextState = produce(baseState, draft => {
	draft[1].done = true
	draft.push({title: "Tweet about it"})
})
```

Looking for Immer in combination with React? Feel free to skip ahead to the [React + Immer](example-setstate) page.

### How Immer works

The basic idea is that with Immer you will apply all your changes to a temporary _draft_, which is a proxy of the _currentState_. Once all your mutations are completed, Immer will produce the _nextState_ based on the mutations to the draft state. This means that you can interact with your data by simply modifying it while keeping all the benefits of immutable data.



Using Immer is like having a personal assistant. The assistant takes a letter (the current state) and gives you a copy (draft) to jot changes onto. Once you are done, the assistant will take your draft and produce the real immutable, final letter for you (the next state).

Head to the [next section](./produce.mdx) to further dive into `produce`.

## Benefits

- Follow the immutable data paradigm, while using normal JavaScript objects, arrays, Sets and Maps. No new APIs or "mutation patterns" to learn!
- Strongly typed, no string based paths selectors etc.
- Structural sharing out of the box
- Object freezing out of the box
- Deep updates are a breeze
- Boilerplate reduction. Less noise, more concise code.
- First class support for JSON patches
- Small: 3KB gzipped

---

### Map Set (`website/docs/map-set.md`)

---
id: map-set
title: Map and Set
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

_⚠ Since version 6 support for `Map`s and `Set`s has to be enabled explicitly by calling [`enableMapSet()`](./installation.mdx#pick-your-immer-version) once when starting your application._

Plain objects, arrays, `Map`s and `Set`s are always drafted by Immer. An example of using Maps with immer:

```javascript
test("Producers can update Maps", () => {
	const usersById_v1 = new Map()

	const usersById_v2 = produce(usersById_v1, draft => {
		// Modifying a map results in a new map
		draft.set("michel", {name: "Michel Weststrate", country: "NL"})
	})

	const usersById_v3 = produce(usersById_v2, draft => {
		// Making a change deep inside a map, results in a new map as well!
		draft.get("michel").country = "UK"
	})

	// We got a new map each time!
	expect(usersById_v2).not.toBe(usersById_v1)
	expect(usersById_v3).not.toBe(usersById_v2)
	// With different content obviously
	expect(usersById_v1).toMatchInlineSnapshot(`Map {}`)
	expect(usersById_v2).toMatchInlineSnapshot(`
		Map {
		  "michel" => Object {
		    "country": "NL",
		    "name": "Michel Weststrate",
		  },
		}
	`)
	expect(usersById_v3).toMatchInlineSnapshot(`
		Map {
		  "michel" => Object {
		    "country": "UK",
		    "name": "Michel Weststrate",
		  },
		}
	`)
	// The old one was never modified
	expect(usersById_v1.size).toBe(0)
	// And trying to change a Map outside a producers is going to: NO!
	expect(() => usersById_v3.clear()).toThrowErrorMatchingInlineSnapshot(
		`"This object has been frozen and should not be mutated"`
	)
})
```

Maps and Sets that are produced by Immer will be made artificially immutable. This means that they will throw an exception when trying mutative methods like `set`, `clear` etc. outside a producer.

_Note: The **keys** of a map are never drafted! This is done to avoid confusing semantics and keep keys always referentially equal_

---

### Original (`website/docs/original.md`)

---
id: original
title: Extracting the original state from a draft
sidebar_label: Original
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

Immer exposes a named export `original` that will get the original object from the proxied instance inside `produce` (or return `undefined` for unproxied values). A good example of when this can be useful is when searching for nodes in a tree-like state using strict equality.

```js
import {original, produce} from "immer"

const baseState = {users: [{name: "Richie"}]}
const nextState = produce(baseState, draftState => {
	original(draftState.users) // is === baseState.users
})
```

Just want to know if a value is a proxied instance? Use the `isDraft` function! Note that `original` cannot be invoked on objects that aren't drafts.

```js
import {isDraft, produce} from "immer"

const baseState = {users: [{name: "Bobby"}]}
const nextState = produce(baseState, draft => {
	isDraft(draft) // => true
	isDraft(draft.users) // => true
	isDraft(draft.users[0]) // => true
})
isDraft(nextState) // => false
```

---

### Other Lang (`website/docs/other-lang.md`)

---
id: other-lang
title: Porting to other languages
---

Immer has been ported to other programming languages.

| Language | Link                                                |
| -------- | --------------------------------------------------- |
| Java     | [Jimmer](https://babyfish-ct.github.io/jimmer-doc/) |

---

### Patches (`website/docs/patches.mdx`)

---
id: patches
title: Patches
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 14: Capture patches using _produceWithPatches_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-capture-patches-to-distribute-changes-in-app-state-with-immer-producewithpatches"
	>
		Hosted on egghead.io
	</a>
</details>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 16: Apply Patches using _applyPatches_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-apply-patches-using-immer-applypatches-to-synchronize-state-across-clients"
	>
		Hosted on egghead.io
	</a>
</details>

_⚠ Since version 6 support for Patches has to be enabled explicitly by calling [`enablePatches()`](./installation.mdx#pick-your-immer-version) once when starting your application._

During the run of a producer, Immer can record all the patches that would replay the changes made by the reducer. This is a very powerful tool if you want to fork your state temporarily and replay the changes to the original.

Patches are useful in few scenarios:

- To exchange incremental updates with other parties, for example over websockets
- For debugging / traces, to see precisely how state is changed over time
- As basis for undo/redo or as an approach to replay changes on a slightly different state tree

To help with replaying patches, `applyPatches` comes in handy. Here is an example how patches could be used to record the incremental updates and (inverse) apply them:

```javascript
import {produce, applyPatches} from "immer"

// version 6
import {enablePatches} from "immer"
enablePatches()

let state = {
	name: "Micheal",
	age: 32
}

// Let's assume the user is in a wizard, and we don't know whether
// his changes should end up in the base state ultimately or not...
let fork = state
// all the changes the user made in the wizard
let changes = []
// the inverse of all the changes made in the wizard
let inverseChanges = []

fork = produce(
	fork,
	draft => {
		draft.age = 33
	},
	// The third argument to produce is a callback to which the patches will be fed
	(patches, inversePatches) => {
		changes.push(...patches)
		inverseChanges.push(...inversePatches)
	}
)

// In the meantime, our original state is replaced, as, for example,
// some changes were received from the server
state = produce(state, draft => {
	draft.name = "Michel"
})

// When the wizard finishes (successfully) we can replay the changes that were in the fork onto the *new* state!
state = applyPatches(state, changes)

// state now contains the changes from both code paths!
expect(state).toEqual({
	name: "Michel", // changed by the server
	age: 33 // changed by the wizard
})

// Finally, even after finishing the wizard, the user might change his mind and undo his changes...
state = applyPatches(state, inverseChanges)
expect(state).toEqual({
	name: "Michel", // Not reverted
	age: 32 // Reverted
})
```

The generated patches are similar (but not the same) to the [RFC-6902 JSON patch standard](https://datatracker.ietf.org/doc/html/rfc6902/#section-4.1), except that the `path` property is an array, rather than a string. This makes processing patches easier. If you want to normalize to the official specification, use `patch.path = "/" + patch.path.join("/")` so the result is a JSON Pointer with a leading `/` (and escape `~` / `/` in path tokens per [RFC-6901](https://datatracker.ietf.org/doc/html/rfc6901) when needed). Anyway, this is what a bunch of patches and their inverse could look like:

```json
[
	{
		"op": "replace",
		"path": ["profile"],
		"value": {"name": "Veria", "age": 5}
	},
	{"op": "remove", "path": ["tags", 3]}
]
```

```json
[
	{"op": "replace", "path": ["profile"], "value": {"name": "Noa", "age": 6}},
	{"op": "add", "path": ["tags", 3], "value": "kiddo"}
]
```

⚠ Note: The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible. It depends often on the use case what is considered 'optimal', and generating the optimal set of patches is potentially computationally very expensive. So in cases you might want to post process the generated patches, or compress them as explained below.

### `produceWithPatches`

<details>
	<summary className="egghead-summary">
		egghead.io lesson 19: Using inverse patches to build undo functionality
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-use-immer-inversepatches-to-build-undo-functionality"
	>
		Hosted on egghead.io
	</a>
</details>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 20: Use patches to build redo functionality
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-use-immer-patches-to-build-redo-functionality"
	>
		Hosted on egghead.io
	</a>
</details>

Instead of setting up a patch listener, an easier way to obtain the patches is to use `produceWithPatches`, which has the same signature as `produce`, except that it doesn't return just the next state, but a tuple consisting of `[nextState, patches, inversePatches]`. Like `produce`, `produceWithPatches` supports currying as well.

```javascript
import {produceWithPatches} from "immer"

const [nextState, patches, inversePatches] = produceWithPatches(
	{
		age: 33
	},
	draft => {
		draft.age++
	}
)
```

Which produces:

```javascript
;[
	{
		age: 34
	},
	[
		{
			op: "replace",
			path: ["age"],
			value: 34
		}
	],
	[
		{
			op: "replace",
			path: ["age"],
			value: 33
		}
	]
]
```

For a more in-depth study, see [Distributing patches and rebasing actions using Immer](https://medium.com/@mweststrate/distributing-state-changes-using-snapshots-patches-and-actions-part-2-2f50d8363988)

Tip: Check this trick to [compress patches](https://medium.com/@david.b.edelstein/using-immer-to-compress-immer-patches-f382835b6c69) produced over time.

---

### Performance (`website/docs/performance.mdx`)

---
id: performance
title: Immer performance
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 5: Leveraging Immer's structural sharing in React
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-profile-react-rendering-and-optimize-with-memo-to-leverage-structural-sharing/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-profile-react-rendering-and-optimize-with-memo-to-leverage-structural-sharing"
	>
		Hosted on egghead.io
	</a>
</details>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 7: Immer will try to re-cycle data if there was no
		semantic change
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/javascript-produces-immutable-data-and-avoid-unnecessary-creation-of-new-data-trees-with-immer/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/javascript-produces-immutable-data-and-avoid-unnecessary-creation-of-new-data-trees-with-immer"
	>
		Hosted on egghead.io
	</a>
</details>

Here is a [simple benchmark](https://github.com/immerjs/immer/blob/main/__performance_tests__/todo.js) on the performance of Immer. This test takes 50,000 todo items and updates 5,000 of them. _Freeze_ indicates that the state tree has been frozen after producing it. This is a _development_ best practice, as it prevents developers from accidentally modifying the state tree.

Something that isn't reflected in the numbers above, but in reality, Immer is sometimes significantly _faster_ than a hand written reducer. The reason for that is that Immer will detect "no-op" state changes, and return the original state if nothing actually changed, which can avoid a lot of re-renderings for example. Cases are known where simply applying immer solved critical performance issues.

These tests were executed on Node 10.16.3. Use `yarn test:perf` to reproduce them locally.



Most important observation:

- Immer with proxies is roughly speaking twice to three times slower as a handwritten reducer (the above test case is worst case, see `yarn test:perf` for more tests). This is in practice negligible.
- Immer is roughly as fast as ImmutableJS. However, the _immutableJS + toJS_ makes clear the cost that often needs to be paid later; converting the immutableJS objects back to plain objects, to be able to pass them to components, over the network etc... (And there is also the upfront cost of converting data received from e.g. the server to immutable JS)
- Generating patches doesn't significantly slow down immer
- The ES5 fallback implementation is roughly twice as slow as the proxy implementation, in some cases worse.

## Performance tips

### Enable the Array Methods Plugin

For applications with significant array iteration within producers, enable the [Array Methods Plugin](./array-methods.md):

```javascript
import {enableArrayMethods} from "immer"
enableArrayMethods()
```

This plugin optimizes array operations like `filter`, `find`, `some`, `every`, and `slice` by avoiding proxy creation for every element during iteration. Without the plugin, iterating a 1000-element array creates 1000+ proxies. With the plugin, callbacks receive base values, and proxies are only created for elements you actually mutate.

### Use loose iteration for better performance

By default, Immer uses loose iteration which only processes enumerable string properties. This is faster than strict iteration which includes symbols and non-enumerable properties. For most use cases, the default is optimal:

```javascript
import {setUseStrictIteration} from "immer"

// Default: false (loose iteration for better performance)
setUseStrictIteration(false)
```

Only enable strict iteration if you specifically need to track symbol or non-enumerable properties.

### Pre-freeze data

When adding a large data set to the state tree in an Immer producer (for example data received from a JSON endpoint), it is worth to call `freeze(json)` on the root of the data that is being added first. To _shallowly_ freeze it. This will allow Immer to add the new data to the tree faster, as it will avoid the need to _recursively_ scan and freeze the new data.

### You can always opt-out

Realize that immer is opt-in everywhere, so it is perfectly fine to manually write super performance critical reducers, and use immer for all the normal ones. Even from within a producer you opt-out from Immer for certain parts of your logic by using utilies `original` or `current` and perform some of your operations on plain JavaScript objects.

### For expensive search operations, read from the original state, not the draft

Immer will convert anything you read in a draft recursively into a draft as well. If you have expensive side effect free operations on a draft that involves a lot of reading, for example finding an index using `find(Index)` in a very large array, you can speed this up by first doing the search, and only call the `produce` function once you know the index. Thereby preventing Immer to turn everything that was searched for in a draft. Or, alternatively, perform the search on the original value of a draft, by using `original(someDraft)`, which boils to the same thing.

### Pull produce as far up as possible

Always try to pull produce 'up', for example `for (let x of y) produce(base, d => d.push(x))` is exponentially slower than `produce(base, d => { for (let x of y) d.push(x)})`

---

### Pitfalls (`website/docs/pitfalls.md`)

---
id: pitfalls
title: Pitfalls
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

### Performance tips

For performance tips, see [Performance Tips](./performance.mdx#performance-tips).

### Don't reassign the recipe argument

Never reassign the `draft` argument (example: `draft = myCoolNewState`). Instead, either modify the `draft` or return a new state. See [Returning data from producers](./return.mdx).

### Immer only supports unidirectional trees

Immer assumes your state to be a unidirectional tree. That is, no object should appear twice in the tree, there should be no circular references. There should be exactly one path from the root to any node of the tree.

### Never explicitly return `undefined` from a producer

It is possible to return values from producers, except, it is not possible to return `undefined` that way, as it is indistinguishable from not updating the draft at all! If you want to replace the draft with `undefined`, just return `nothing` from the producer.

### Don't mutate exotic objects

Immer [does not support exotic objects](https://github.com/immerjs/immer/issues/504) such as window.location.

### Classes should be made draftable or not mutated

You will need to enable your own classes to work properly with Immer. For docs on the topic, check out the section on [working with complex objects](./complex-objects.md).

### Only valid indices and length can be mutated on Arrays

For arrays, only numeric properties and the `length` property can be mutated. Custom properties are not preserved on arrays.

### Data not originating from the state will never be drafted

Note that data that comes from the closure, and not from the base state, will never be drafted, even when the data has become part of the new draft.

```javascript
function onReceiveTodo(todo) {
	const nextTodos = produce(todos, draft => {
		draft.todos[todo.id] = todo
		// Note, because 'todo' is coming from external, and not from the 'draft',
		// it isn't draft so the following modification affects the original todo!
		draft.todos[todo.id].done = true

		// The reason for this, is that it means that the behavior of the 2 lines above
		// is equivalent to code, making this whole process more consistent
		todo.done = true
		draft.todos[todo.id] = todo
	})
}
```

### Immer patches are not necessarily optimal

The set of patches generated by Immer should be correct, that is, applying them to an equal base object should result in the same end state. However Immer does not guarantee the generated set of patches will be optimal, that is, the minimum set of patches possible.

### Always use the result of nested producers

Nested `produce` calls are supported, but note that `produce` will _always_ produce a new state. So even when passing a draft to a nested produce, the changes made by the inner produce won't be visible in the draft of the outer produce; those changes will only be visible in the output that the inner `produce` returns. In other words, when using nested produce, you get a draft of a draft and the result of the inner produce should be merged back into the original draft (or returned). For example `produce(state, draft => { produce(draft.user, userDraft => { userDraft.name += "!" })})` won't work as the output of the inner produce isn't used. The correct way to use nested producers is:

```javascript
produce(state, draft => {
	draft.user = produce(draft.user, userDraft => {
		userDraft.name += "!"
	})
})
```

### Drafts aren't referentially equal

Draft objects in Immer are wrapped in `Proxy`, so you cannot use `==` or `===` to test equality between an original object and its equivalent draft (eg. when matching a specific element in an array). Instead, you can use the `original` helper:

```javascript
const remove = produce((list, element) => {
	const index = list.indexOf(element) // this won't work!
	const index = original(list).indexOf(element) // do this instead
	if (index > -1) list.splice(index, 1)
})

const values = [a, b, c]
remove(values, a)
```

If possible, it's recommended to perform the comparison outside the `produce` function, or to use a unique identifier property like `.id` instead, to avoid needing to use `original`.

### Array Methods Plugin: Callbacks receive base values

When using the [Array Methods Plugin](./array-methods.md) (`enableArrayMethods()`), callbacks for overridden methods like `filter`, `find`, `some`, `every`, and `slice` receive **base values** (not drafts). This is the core performance optimization - it avoids creating proxies for every element during iteration.

```javascript
import {enableArrayMethods, produce} from "immer"
enableArrayMethods()

produce(state, draft => {
	draft.items.filter(item => {
		// `item` is a base value here, NOT a draft
		// Reading works fine:
		return item.value > 10

		// But direct mutation here won't be tracked:
		// item.value = 999  // ❌ Won't affect the draft!
	})

	// Instead, use the returned result (which contains drafts):
	const filtered = draft.items.filter(item => item.value > 10)
	filtered[0].value = 999 // ✅ This works - filtered[0] is a draft
})
```

This only applies to methods intercepted by the plugin. Methods like `map`, `forEach`, `reduce` are NOT overridden and work normally - their callbacks receive drafts.

---

### Produce (`website/docs/produce.mdx`)

---
id: produce
title: Using produce
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center> <details>
	<summary className="egghead-summary">
		egghead.io lesson 3: Simplifying deep updates with _produce_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/javascript-simplify-deep-state-updates-using-immer-produce/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/javascript-simplify-deep-state-updates-using-immer-produce"
	>
		Hosted on egghead.io
	</a>
</details>

The Immer package exposes a `produce` function that does all the work.

`produce(baseState, recipe: (draftState) => void): nextState`

`produce` takes a base state, and a _recipe_ that can be used to perform all the desired mutations on the `draft` that is passed in. The interesting thing about Immer is that the `baseState` will be untouched, but the `nextState` will reflect all changes made to `draftState`.

Inside the recipe, all standard JavaScript APIs can be used on the `draft` object, including field assignments, `delete` operations, and mutating array, Map and Set operations like `push`, `pop`, `splice`, `set`, `sort`, `remove`, etc.

Any of those mutations don't have to happen at the root, but it is allowed to modify anything anywhere deep inside the draft: `draft.todos[0].tags["urgent"].author.age = 56`

Note that the recipe function itself normally doesn't return anything. However, it is possible to return in case you want to replace the `draft` object in its entirety with another object, for more details see [returning new data](./return.mdx).

## Example

```javascript
import {produce} from "immer"

const baseState = [
	{
		title: "Learn TypeScript",
		done: true
	},
	{
		title: "Try Immer",
		done: false
	}
]

const nextState = produce(baseState, draftState => {
	draftState.push({title: "Tweet about it"})
	draftState[1].done = true
})
```

```javascript
// the new item is only added to the next state,
// base state is unmodified
expect(baseState.length).toBe(2)
expect(nextState.length).toBe(3)

// same for the changed 'done' prop
expect(baseState[1].done).toBe(false)
expect(nextState[1].done).toBe(true)

// unchanged data is structurally shared
expect(nextState[0]).toBe(baseState[0])
// ...but changed data isn't.
expect(nextState[1]).not.toBe(baseState[1])
```

For advanced TypeScript typing scenarios, see [Using TypeScript or Flow](./typescript.mdx).

### Terminology

- `(base)state`, the immutable state passed to `produce`
- `recipe`: the second argument of `produce`, that captures how the base state should be "mutated".
- `draft`: the first argument of any `recipe`, which is a proxy to the original base state that can be safely mutated.
- `producer`. A function that uses `produce` and is generally of the form `(baseState, ...arguments) => resultState`

Note that it isn't strictly necessary to name the first argument of the recipe `draft`. You can name it anything you want, for example `users`. Using `draft` as a name is just a convention to signal: "mutation is OK here".

---

### Resources (`website/docs/resources.md`)

---
id: resources
title: External resources
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

- Blog: [The Rise of Immer in React](https://www.netlify.com/blog/2018/09/12/the-rise-of-immer-in-react/)
- Blog: by Workday Prism on why they picked Immer to manage immutable state [The Search for a Strongly-Typed, Immutable State](https://medium.com/workday-engineering/workday-prism-analytics-the-search-for-a-strongly-typed-immutable-state-a09f6768b2b5)
- Blog: [Immutability in React and Redux: The Complete Guide](https://daveceddia.com/react-redux-immutability-guide/)
- Video tutorial: [Using Immer with React.setState](https://codedaily.io/screencasts/86/Immutable-Data-with-Immer-and-React-setState)
- [Talk](https://www.youtube.com/watch?v=-gJbS7YjcSo) + [slides](http://immer.surge.sh/) on Immer at React Finland 2018 by Michel Weststrate
- [ForwardJS 2019: Immutability is Changing - From Immutable.js to Immer](https://www.youtube.com/watch?v=bFuRvcAEiHg&feature=youtu.be) by [shawn swyx wang](https://twitter.com/swyx/)
- [Talk: Immer, Immutability and the Wonderful World of Proxies](https://www.youtube.com/watch?v=4Nb9Gwp2L24) + [slides](https://jsnation-proxies.surge.sh/), JSNation 2019, Michel Weststrate
- Blog: [Distributing state changes using snapshots, patches and actions](https://medium.com/@mweststrate/distributing-state-changes-using-snapshots-patches-and-actions-part-1-2811a2fcd65f)
- Blog: [Implementing Undo-Redo Functionality in Redux](https://techinscribed.com/implementing-undo-redo-functionality-in-redux-using-immer/), Sep 2019
- Blog: [Synchronized immutable state with time travel](https://dev.to/oleg008/synchronized-immutable-state-with-time-travel-2c6o), Apr 2022, by [Oleg Isonen](https://twitter.com/oleg008)

---

### Return (`website/docs/return.mdx`)

---
id: return
title: Returning new data from producers
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>
<details>
	<summary className="egghead-summary">
		egghead.io lesson 9: Returning completely new state
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-return-completely-new-state-from-an-immer-producer/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-return-completely-new-state-from-an-immer-producer"
	>
		Hosted on egghead.io
	</a>
</details>

It is not needed to return anything from a producer, as Immer will return the (finalized) version of the `draft` anyway. However, it is allowed to just `return draft`.

It is also allowed to return arbitrarily other data from the producer function. But _only_ if you didn't modify the draft. This can be useful to produce an entirely new state. Some examples:

```javascript
const userReducer = produce((draft, action) => {
	switch (action.type) {
		case "renameUser":
			// OK: we modify the current state
			draft.users[action.payload.id].name = action.payload.name
			return draft // same as just 'return'
		case "loadUsers":
			// OK: we return an entirely new state
			return action.payload
		case "adduser-1":
			// NOT OK: This doesn't do change the draft nor return a new state!
			// It doesn't modify the draft (it just redeclares it)
			// In fact, this just doesn't do anything at all
			draft = {users: [...draft.users, action.payload]}
			return
		case "adduser-2":
			// NOT OK: modifying draft *and* returning a new state
			draft.userCount += 1
			return {users: [...draft.users, action.payload]}
		case "adduser-3":
			// OK: returning a new state. But, unnecessary complex and expensive
			return {
				userCount: draft.userCount + 1,
				users: [...draft.users, action.payload]
			}
		case "adduser-4":
			// OK: the immer way
			draft.userCount += 1
			draft.users.push(action.payload)
			return
	}
})
```

_Note: It is not possible to return `undefined` this way, as it is indistinguishable from *not* updating the draft! Read on..._

## Producing `undefined` using `nothing`

So, in general, one can replace the current state by just `return`ing a new value from the producer, rather than modifying the draft. There is a subtle edge case however: if you try to write a producer that wants to replace the current state with `undefined`:

```javascript
produce({}, draft => {
	// don't do anything
})
```

Versus:

```javascript
produce({}, draft => {
	// Try to return undefined from the producer
	return undefined
})
```

The problem is that in JavaScript a function that doesn't return anything also returns `undefined`! So immer cannot differentiate between those different cases. So, by default, Immer will assume that any producer that returns `undefined` just tried to modify the draft.

However, to make it clear to Immer that you intentionally want to produce the value `undefined`, you can return the built-in token `nothing`:

```javascript
import {produce, nothing} from "immer"

const state = {
	hello: "world"
}

produce(state, draft => {})
produce(state, draft => undefined)
// Both return the original state: { hello: "world"}

produce(state, draft => nothing)
// Produces a new state, 'undefined'
```

N.B. Note that this problem is specific for the `undefined` value, any other value, including `null`, doesn't suffer from this issue.

Tip: to be able to return `nothing` from a recipe when using TypeScript, the `state`'s type must accept `undefined` as value.

## Inline shortcuts using `void`

<details>
	<summary className="egghead-summary">
		egghead.io lesson 10: Avoid accidental returns by using _void_
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-avoid-accidental-returns-of-new-state-by-using-the-void-keyword/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-avoid-accidental-returns-of-new-state-by-using-the-void-keyword"
	>
		Hosted on egghead.io
	</a>
</details>

Draft mutations in Immer usually warrant a code block, since a return denotes an overwrite. Sometimes that can stretch code a little more than you might be comfortable with.

In such cases, you can use javascripts [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void) operator, which evaluates expressions and returns `undefined`.

```javascript
// Single mutation
produce(draft => void (draft.user.age += 1))

// Multiple mutations
produce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))
```

Code style is highly personal, but for code bases that are to be understood by many, we recommend to stick to the classic `draft => { draft.user.age += 1}` to avoid cognitive overhead.

---

### Support (`website/docs/support.md`)

---
id: support
title: Supporting immer
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

Immer currently has 350.000 dependents on GitHub, and has almost 10.000.000 downloads per month. However, only the first 2 days of development has been sponsored (by Mendix), and all the development and maintenance after that has been a labor of love.

If you are enjoying Immer, and you are grateful for the package, or want to ensure its longevity, consider sponsoring the open collective on https://opencollective.com/immer or make a one time donation using [PayPal](https://www.paypal.me/michelweststrate).

---

### Typescript (`website/docs/typescript.mdx`)

---
id: typescript
title: Using TypeScript or Flow
sidebar_label: TypeScript / Flow
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center> <details>
	<summary className="egghead-summary">
		egghead.io lesson 12: Immer + TypeScript
	</summary>
	<br />
	<div>
		<iframe
			width="760"
			height="427"
			scrolling="no"
			src="https://egghead.io/lessons/react-type-immutable-immer-data-with-typescript/embed"
		></iframe>
	</div>
	<a
		className="egghead-link"
		href="https://egghead.io/lessons/react-type-immutable-immer-data-with-typescript"
	>
		Hosted on egghead.io
	</a>
</details>

The Immer package ships with type definitions inside the package, which should be picked up by TypeScript and Flow out of the box and without further configuration.

The TypeScript typings automatically remove `readonly` modifiers from your draft types and return a value that matches your original type. See this practical example:

```ts
import {produce} from "immer"

interface State {
	readonly x: number
}

// `x` cannot be modified here
const state: State = {
	x: 0
}

const newState = produce(state, draft => {
	// `x` can be modified here
	draft.x++
})

// `newState.x` cannot be modified here
```

This ensures that the only place you can modify your state is in your produce callbacks. It even works recursively and with `ReadonlyArray`.

## Best practices

1. Always define your states as `readonly` as much as possible. This best reflects the mental model and reality, since Immer will freeze all its returned values.
2. You can use the utility type `Immutable` to recursively make an entire type tree read-only, e.g.: `type ReadonlyState = Immutable<State>`.
3. Immer won't automatically wrap all returned types in `Immutable` if the original type of the input state wasn't immutable. This is to make sure it doesn't break code bases that don't use immutable types.

## Typing reusable recipes

If you want to pass a recipe callback around, you can type it using `Draft` and allow either `void` or a replacement state as the return value.

```ts
import {produce} from "immer"
import type {Draft} from "immer"

type Recipe<S> = (draft: Draft<S>) => void | S

function updateState<S>(
	setState: (updater: (prev: S) => S) => void,
	recipe: Recipe<S>
) {
	setState(prev => produce(prev, recipe))
}
```

### React example

A common usage in React is to wrap `setState` with `produce` so callers can provide a typed recipe.

```tsx
import {produce} from "immer"
import type {Draft} from "immer"
import {useCallback, useState} from "react"

type State = {
	foo: string
	bar: string
}

const initialState: State = {
	foo: "",
	bar: ""
}

type Recipe = (draft: Draft<State>) => void | State

export function Example() {
	const [state, setState] = useState<State>(initialState)

	const updateState = useCallback((recipe: Recipe) => {
		setState(prev => produce(prev, recipe))
	}, [])

	return (
		<button
			onClick={() => {
				updateState(draft => {
					draft.foo = "Muffin Man" // this recipe is typed
				})
			}}
			type="button"
		>
			Hello {state.foo}
		</button>
	)
}
```

## Tips for curried producers

We try to inference as much as possible. So if a curried producer is created and directly passed to another function, we can infer the type from there. This works well with for example React:

```typescript
import {Immutable, produce} from "immer"

type Todo = Immutable<{
	title: string
	done: boolean
}>

// later...

const [todo, setTodo] = useState<Todo>({
	title: "test",
	done: true
})

// later...

setTodo(
	produce(draft => {
		// draft will be strongly typed and mutable!
		draft.done = !draft.done
	})
)
```

When a curried producer isn't passed directly somewhere else, Immer can infer the state type from the draft argument. For example when doing the following:

```typescript
// See below for a better solution!

const toggler = produce((draft: Draft<Todo>) => {
	draft.done = !draft.done
})

// typeof toggler = (state: Immutable<Todo>) => Writable<Todo>
```

Note that we did wrap the `Todo` type of the `draft` argument with `Draft`, because `Todo` is a readonly type. For non-readonly types this isn't needed.

For the returned curried function, `toggler`, We will _narrow_ the _input_ type to `Immutable<Todo>`, so that even though `Todo` is a mutable type, we will still accept an immutable todo as input argument to `toggler`.

In contrast, Immer will _widen_ the _output_ type of the curried function to `Writable<Todo>`, to make sure it's output state is also assignable to variables that are not explicitly typed to be immutable.

This type narrowing / widening behavior might be unwelcome, maybe even for the simple reason that it results in quite noisy types. So we recommend to specify the generic state type for curried producers instead, in cases where it cannot be inferred directly, like `toggler` above. By doing so the automatic output widening / input narrowing will be skipped. However, the `draft` argument itself will still be inferred to be a writable `Draft<Todo>`:

```typescript
const toggler = produce<Todo>(draft => {
	draft.done = !draft.done
})

// typeof toggler = (state: Todo) => Todo
```

However, in case the curried producer is defined with an initial state, Immer can infer the state type from the initial state, so in that case the generic doesn't need to be specified either:

```typescript
const state0: Todo = {
	title: "test",
	done: false
}

// No type annotations needed, since we can infer from state0.
const toggler = produce(draft => {
	draft.done = !draft.done
}, state0)

// typeof toggler = (state: Todo) => Todo
```

In case the toggler has no initial state, and it has curried arguments, and you set the state generic explicitly, then type of any additional arguments should be defined explicitly as a tuple type as well:

```typescript
const toggler = produce<Todo, [boolean]>((draft, newState) => {
	draft.done = newState
})

// typeof toggler = (state: Todo, newState: boolean) => Todo
```

## Cast utilities

The types inside and outside a `produce` can be conceptually the same, but from a practical perspective different. For example, the `State` in the examples above should be considered immutable outside `produce`, but mutable inside `produce`.

Sometimes this leads to practical conflicts. Take the following example:

```typescript
type Todo = {readonly done: boolean}

type State = {
	readonly finishedTodos: readonly Todo[]
	readonly unfinishedTodos: readonly Todo[]
}

function markAllFinished(state: State) {
	produce(state, draft => {
		draft.finishedTodos = state.unfinishedTodos
	})
}
```

This will generate the error:

```
The type 'readonly Todo[]' is 'readonly' and cannot be assigned to the mutable type '{ done: boolean; }[]'
```

The reason for this error is that we assign our read only, immutable array to our draft, which expects a mutable type, with methods like `.push` etc etc. As far as TS is concerned, those are not exposed from our original `State`. To hint TypeScript that we want to upcast the collection here to a mutable array for draft purposes, we can use the utility `castDraft`:

`draft.finishedTodos = castDraft(state.unfinishedTodos)` will make the error disappear.

There is also the utility `castImmutable`, in case you ever need to achieve the opposite. Note that these utilities are for all practical purposes no-ops, they will just return their original value.

Tip: You can combine `castImmutable` with `produce` to type the return type of `produce` as something immutable, even when the original state was mutable:

```typescript
// a mutable data structure
const baseState = {
	todos: [{
		done: false
	}]
}

const nextState = castImmutable(produce(baseState, _draft => {}))

// inferred type of nextState is now:
{
	readonly todos: ReadonlyArray<{
		readonly done: boolean
	}>
})
```

## Compatibility

**Note:** Immer v5.3+ supports TypeScript v3.7+ only.

**Note:** Immer v3.0+ supports TypeScript v3.4+ only.

**Note:** Immer v1.9+ supports TypeScript v3.1+ only.

**Note:** Flow support might be removed in future versions and we recommend TypeScript

---

### Update Patterns (`website/docs/update-patterns.md`)

---
id: update-patterns
title: Update patterns
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" className="horizontal bordered"></div>
</center>

Working with immutable data, before Immer, used to mean learning all the immutable update patterns.

To help 'unlearning' those patterns here is an overview how you can leverage the built-in JavaScript APIs to update objects and collections:

### Object mutations

```javascript
import {produce} from "immer"

const todosObj = {
	id1: {done: false, body: "Take out the trash"},
	id2: {done: false, body: "Check Email"}
}

// add
const addedTodosObj = produce(todosObj, draft => {
	draft["id3"] = {done: false, body: "Buy bananas"}
})

// delete single property
const deletedTodosObj = produce(todosObj, draft => {
	delete draft["id1"]
})

// update
const updatedTodosObj = produce(todosObj, draft => {
	draft["id1"].done = true
})

// replace & update in bulk
const updatedTodosObj = produce(todosObj, draft => {
	Object.assign(draft, {
		id1: {done: true, body: "Take out the trash"},
		id2: {done: true, body: "Check Email"},
		id3: {done: true, body: "Feed my cat"}
	})

// reset/clear/empty
const emptyTodo = produce(todosObj, () => {
	return {};
})
```

Any time a nested draft field gets a new reference or value, produce() will finish applying the immutable update and return a new reference. If you tried to mutate, but the values remained the same, Immer will bail out and return the existing reference from produce()

### Array mutations

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Nested data structures

```javascript
import {produce} from "immer"

// example complex data structure
const store = {
	users: new Map([
		[
			"17",
			{
				name: "Michel",
				todos: [
					{
						title: "Get coffee",
						done: false
					}
				]
			}
		]
	])
}

// updating something deeply in-an-object-in-an-array-in-a-map-in-an-object:
const nextStore = produce(store, draft => {
	draft.users.get("17").todos[0].done = true
})

// filtering out all unfinished todo's
const nextStore = produce(store, draft => {
	const user = draft.users.get("17")
	// when filtering, creating a fresh collection is simpler than
	// removing irrelevant items
	user.todos = user.todos.filter(todo => !todo.done)
})
```

Note that many array operations can be used to insert multiple items at once by passing multiple arguments or using the spread operation: `todos.unshift(...items)`.

Note that when working with arrays that contain objects that are typically identified by some id, we recommend to use `Map` or index based objects (as shown above) instead of performing frequent find operations, lookup tables perform much better in general.

---

--- METRICS ---
- Files Extracted: 26
- Estimated Token Budget: ~22907 tokens
- Canonical Reference: https://codewiki.google/github.com/immerjs/immer
