### Installation Source: https://github.com/unadlib/mutative/blob/main/website/README.md Installs project dependencies using Yarn. ```bash $ yarn ``` -------------------------------- ### Currying with Options Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/create.md An example demonstrating how to use `create()` with currying and options. ```typescript const [draft, finalize] = create(baseState, { enableAutoFreeze: true }); ``` -------------------------------- ### Installation Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/mutative-with-react.md Install mutative and use-mutative packages using npm or yarn. ```bash npm install mutative use-mutative ``` -------------------------------- ### Local Development Source: https://github.com/unadlib/mutative/blob/main/website/README.md Starts a local development server for live previewing changes. ```bash $ yarn start ``` -------------------------------- ### Install Mutative Source: https://github.com/unadlib/mutative/blob/main/website/blog/releases/1.0/index.md Install Mutative using Yarn or NPM. ```bash yarn add mutative ``` -------------------------------- ### Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/create.md A basic example demonstrating how to use `create()` to mutate a state immutably. ```typescript import { create } from 'mutative'; const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const state = create(baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); }); ``` -------------------------------- ### Install Mutative using npm, Yarn, or pnpm Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/installation.md This command installs the Mutative package using your preferred package manager. ```bash npm install mutative ``` -------------------------------- ### Enable patches Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/pathes.md Example demonstrating how to enable patches and use them to get the state, patches, and inverse patches. ```typescript import { create, apply } from 'mutative'; const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const [state, patches, inversePatches] = create( baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); }, { enablePatches: true, } ); const nextState = apply(baseState, patches); expect(nextState).toEqual(state); const prevState = apply(state, inversePatches); expect(prevState).toEqual(baseState); expect(patches).toMatchInlineSnapshot( ` [ { "op": "add", "path": [ "list", 1, ], "value": { "text": "learning", }, }, { "op": "replace", "path": [ "foo", ], "value": "foobar", }, ] ` ); expect(inversePatches).toMatchInlineSnapshot( ` [ { "op": "replace", "path": [ "list", "length", ], "value": 1, }, { "op": "replace", "path": [ "foo", ], "value": "bar", }, ] ` ); ``` -------------------------------- ### Mutative Immutable Update Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/intro.md An example demonstrating how to perform immutable updates using the Mutative library, showing a more concise and intuitive approach. ```javascript import { create } from 'mutative'; const nextState = create(state, (draft) => { draft.list[2].done = true; draft.list.push({ text: 'Learn Mutative', done: true }); }); ``` -------------------------------- ### apply() example Source: https://github.com/unadlib/mutative/blob/main/README.md Use `apply()` for applying patches to get the new state. ```typescript import { create, apply } from 'mutative'; const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const [state, patches, inversePatches] = create( baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); }, { enablePatches: true, } ); const nextState = apply(baseState, patches); expect(nextState).toEqual(state); const prevState = apply(state, inversePatches); expect(prevState).toEqual(baseState); ``` -------------------------------- ### current() Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/current.md Demonstrates how to use the current() API to get a snapshot of the draft state. ```typescript const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const state = create(baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); expect(current(draft.list)).toEqual([{ text: 'todo' }, { text: 'learning' }]); }); ``` -------------------------------- ### Immer produceWithPatches() example Source: https://github.com/unadlib/mutative/blob/main/README.md Shows how to use Immer's produceWithPatches and applyPatches. ```typescript import { produceWithPatches, applyPatches } from 'immer'; enablePatches(); const baseState = { age: 33, }; const [nextState, patches, inversePatches] = produceWithPatches( baseState, (draft) => { draft.age++; } ); const state = applyPatches(nextState, inversePatches); expect(state).toEqual(baseState); ``` -------------------------------- ### Example Source: https://github.com/unadlib/mutative/blob/main/docs/functions/makeCreator.md This example demonstrates how to use makeCreator to create a state object with auto-freezing enabled. ```typescript import { makeCreator } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const create = makeCreator({ enableAutoFreeze: true }); const state = create( baseState, (draft) => { draft.foo.bar = 'str2'; }, ); expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] }); expect(state).not.toBe(baseState); expect(state.foo).not.toBe(baseState.foo); expect(state.arr).toBe(baseState.arr); expect(Object.isFrozen(state)).toBeTruthy(); ``` -------------------------------- ### Traditional Immutable Update Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/intro.md An example demonstrating how to perform immutable updates using traditional JavaScript spread and slice operations. ```javascript const state = { list: [ { text: 'Learn TypeScript', done: true }, { text: 'Learn React', done: true }, { text: 'Learn Redux', done: false }, ], }; const nextState = { ...state, list: [ ...state.list.slice(0, 2), { ...state.list[2], done: true, }, { text: 'Learn Mutative', done: true }, ], }; ``` -------------------------------- ### Mutative create() example Source: https://github.com/unadlib/mutative/blob/main/README.md Demonstrates the equivalent usage of Mutative's create function for the Immer produce() example. ```typescript import { create } from 'mutative'; const nextState = create(baseState, (draft) => { draft[1].done = true; draft.push({ title: 'something' }); }); ``` -------------------------------- ### makeCreator() example Source: https://github.com/unadlib/mutative/blob/main/README.md Demonstrates how to use makeCreator to create a custom create function with options like enablePatches. ```typescript const baseState = { foo: { bar: 'str', }, }; const create = makeCreator({ enablePatches: true, }); const [state, patches, inversePatches] = create(baseState, (draft) => { draft.foo.bar = 'new str'; }); ``` -------------------------------- ### Example Source: https://github.com/unadlib/mutative/blob/main/docs/functions/create.md Example usage of the create function to modify a nested property. ```typescript import { create } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const state = create( baseState, (draft) => { draft.foo.bar = 'str2'; }, ); expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] }); expect(state).not.toBe(baseState); expect(state.foo).not.toBe(baseState.foo); expect(state.arr).toBe(baseState.arr); ``` -------------------------------- ### Immer produce() example Source: https://github.com/unadlib/mutative/blob/main/README.md Illustrates the usage of Immer's produce function. ```typescript import produce from 'immer'; const nextState = produce(baseState, (draft) => { draft[1].done = true; draft.push({ title: 'something' }); }); ``` -------------------------------- ### Mutative create() with patches example Source: https://github.com/unadlib/mutative/blob/main/README.md Demonstrates Mutative's create function with enablePatches and apply. ```typescript import { create, apply } from 'mutative'; const baseState = { age: 33, }; const [nextState, patches, inversePatches] = create( baseState, (draft) => { draft.age++; }, { enablePatches: true, } ); const state = apply(nextState, inversePatches); expect(state).toEqual(baseState); ``` -------------------------------- ### useMutative Hook Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/mutative-with-react.md Demonstrates how to use the `useMutative` hook to manage React state immutably with mutable operations. Includes examples of updating state via a draft and directly overriding the state. ```tsx export function App() { const [state, setState] = useMutative( { foo: 'bar', list: [ { text: 'todo' }, ], }, ); } ``` -------------------------------- ### original function usage Source: https://github.com/unadlib/mutative/blob/main/README.md Example demonstrating how original() retrieves the initial state of a draft. ```typescript const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const state = create(baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); expect(original(draft.list)).toEqual([{ text: 'todo' }]); }); ``` -------------------------------- ### Include Mutative from CDN Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/installation.md These script tags allow you to include Mutative directly in your HTML for browser usage. ```html ``` ```html ``` -------------------------------- ### Patches with Immer Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/migration.md Example of using Immer's produceWithPatches and applyPatches to track changes. ```typescript import { produceWithPatches, applyPatches } from 'immer'; enablePatches(); const baseState = { info: { name: 'Michael', age: 33, }, }; const [nextState, patches, inversePatches] = produceWithPatches( baseState, (draft) => { draft.info.age++; } ); const state = applyPatches(nextState, inversePatches); expect(state).toEqual(baseState); ``` -------------------------------- ### Base Workflow Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/concepts.md Demonstrates the Mutative workflow by creating a new state from a base state with modifications. It shows how drafts are created and how changes are applied immutably. ```typescript const baseState = { a0: { b0: {}, }, a1: { b1: {}, b2: { c0: 0, }, }, a2: {}, } const nextState = create(baseState, (draft) => { const { a0 } = draft; // If it is draftable, once it has been accessed, it will generate a corresponding draft. expect(isDraft(a0)).toBeTruthy(); // each node is a proxy object draft.a1.b2.c0 = 1; }); expect(nextState).not.toBe(baseState); expect(nextState.a0).toBe(baseState.a0); // generated draft, but not changed expect(nextState.a2).toBe(baseState.a2); // no generated draft, not changed expect(nextState.a1).not.toBe(baseState.a1); expect(nextState.a1.b2).not.toBe(baseState.a1.b2); expect(nextState.a1.b2.c0).toBe(1); ``` -------------------------------- ### original() Example Source: https://github.com/unadlib/mutative/blob/main/docs/functions/original.md Demonstrates how to use the original() function to retrieve the original state within a draft mutation. ```typescript import { create, original } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const state = create( baseState, (draft) => { draft.foo.bar = 'str2'; expect(original(draft.foo)).toEqual({ bar: 'str' }); } ); ``` -------------------------------- ### Applying Patches to State Source: https://github.com/unadlib/mutative/blob/main/docs/functions/apply.md This example demonstrates how to use the apply() function to apply generated patches to the original base state, verifying the result and the patches themselves. ```typescript import { create, apply } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const [state, patches] = create( baseState, (draft) => { draft.foo.bar = 'str2'; }, { enablePatches: true } ); expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] }); expect(patches).toEqual([{ op: 'replace', path: ['foo', 'bar'], value: 'str2' }]); expect(state).toEqual(apply(baseState, patches)); ``` -------------------------------- ### Patches with Mutative Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/migration.md Example of using Mutative's create and apply functions with enablePatches option. ```typescript import { create, apply } from 'mutative'; const baseState = { info: { name: 'Michael', age: 33, }, }; const [nextState, patches, inversePatches] = create( baseState, (draft) => { draft.info.age++; }, { enablePatches: true, } ); const state = apply(nextState, inversePatches); expect(state).toEqual(baseState); ``` -------------------------------- ### pathAsArray - default: true Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/pathes.md Example demonstrating the `pathAsArray` option with `enablePatches` set to false. ```typescript const data = { list: [1, 2, 3] }; const [state, patches, inversePatches] = create( data, (draft) => { draft.list.length = 0; }, { enablePatches: { pathAsArray: false, arrayLengthAssignment: true, }, } ); expect(state).toMatchInlineSnapshot( ` { "list": [], } ` ); expect(patches).toMatchInlineSnapshot( ` [ { "op": "replace", "path": "/list/length", "value": 0, }, ] ` ); expect(inversePatches).toMatchInlineSnapshot( ` [ { "op": "add", "path": "/list/0", "value": 1, }, { "op": "add", "path": "/list/1", "value": 2, }, { "op": "add", "path": "/list/2", "value": 3, }, ] ` ); ``` -------------------------------- ### makeCreator Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/makecreator.md Demonstrates how to use makeCreator to create a custom create function and then use it to modify state, including options for enabling patches and overriding default options. ```typescript const baseState = { foo: { bar: 'str', }, }; const create = makeCreator({ enablePatches: true, }); const [state, patches, inversePatches] = create(baseState, (draft) => { draft.foo.bar = 'new str'; }); // you can use the custom `create()` function option to override the default `makeCreator()` options like this: const nextState = create( baseState, (draft) => { draft.foo.bar = 'new str'; }, { enablePatches: false, } ); ``` -------------------------------- ### Mutative vs Reducer benchmark by object Source: https://github.com/unadlib/mutative/blob/main/README.md Example of updating an object using a naive handcrafted reducer and Mutative. ```typescript // baseState type: Record const state = { ...baseState, key0: { ...baseState.key0, value: i, }, }; ``` ```typescript const state = create(baseState, (draft) => { draft.key0.value = i; }); ``` -------------------------------- ### rawReturn Example Source: https://github.com/unadlib/mutative/blob/main/docs/functions/rawReturn.md Use rawReturn() to wrap the return value to skip the draft check and thus improve performance. ```typescript import { create, rawReturn } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const state = create( baseState, (draft) => { return rawReturn(baseState); }, ); expect(state).toBe(baseState); ``` -------------------------------- ### markSimpleObject Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/marksimplebject.md Demonstrates how to use markSimpleObject() to mark all objects as immutable within a mutable state. ```typescript const baseState = { foo: { bar: 'str', }, simpleObject: Object.create(null), }; const state = create( baseState, (draft) => { draft.foo.bar = 'new str'; draft.simpleObject.a = 'a'; }, { mark: markSimpleObject, } ); expect(state.simpleObject).not.toBe(baseState.simpleObject); ``` -------------------------------- ### produce() -> create() with Mutative Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/migration.md Example of using Mutative's create function, which is a drop-in replacement for Immer's produce. ```typescript import { create } from 'mutative'; const baseState = { list: [{ text: 'coding' }, { text: 'learning' }], }; const nextState = create(baseState, (draft) => { draft[1].done = true; draft.push({ title: 'something' }); }); ``` -------------------------------- ### produce() -> create() with Immer Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/migration.md Example of using Immer's produce function to modify state. ```typescript import produce from 'immer'; const baseState = { list: [{ text: 'coding' }, { text: 'learning' }], }; const nextState = produce(baseState, (draft) => { draft[1].done = true; draft.push({ title: 'something' }); }); ``` -------------------------------- ### Naive handcrafted reducer for object update Source: https://github.com/unadlib/mutative/blob/main/website/blog/releases/1.0/index.md Example of a naive handcrafted reducer for updating an object immutably. ```typescript const state = { ...baseState, key0: { ...baseState.key0, value: i, }, }; ``` -------------------------------- ### Using rawReturn() to return undefined Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/rawreturn.md This example demonstrates how to use rawReturn() to explicitly return undefined from a state mutation, bypassing the draft mechanism. ```typescript const baseState = { id: 'test' }; const state = create(baseState as { id: string } | undefined, (draft) => { return rawReturn(undefined); }); expect(state).toBe(undefined); ``` -------------------------------- ### Mutative vs Reducer benchmark by array Source: https://github.com/unadlib/mutative/blob/main/README.md Examples of updating an array using different naive handcrafted reducer approaches and Mutative. ```typescript // baseState type: { value: number }[] // slower 6x than Mutative const state = [ { ...baseState[0], value: i }, ...baseState.slice(1, baseState.length), ]; // slower 2.5x than Mutative // const state = baseState.map((item, index) => // index === 0 ? { ...item, value: i } : item // ); // same performance as Mutative // const state = [...baseState]; // state[0] = { ...baseState[0], value: i }; ``` ```typescript const state = create(baseState, (draft) => { draft[0].value = i; }); ``` -------------------------------- ### current function usage Source: https://github.com/unadlib/mutative/blob/main/README.md Example showing how current() returns new references for modified nodes and original references for unmodified nodes. ```typescript const state = create({ a: { b: { c: 1 } }, d: { f: 1 } }, (draft) => { draft.a.b.c = 2; expect(current(draft.a)).toEqual({ b: { c: 2 } }); // The node `a` has been modified. expect(current(draft.a) === current(draft.a)).toBeFalsy(); // The node `d` has not been modified. expect(current(draft.d) === current(draft.d)).toBeTruthy(); }); ``` -------------------------------- ### unsafe() Example Source: https://github.com/unadlib/mutative/blob/main/docs/functions/unsafe.md Demonstrates how to use the unsafe() function to modify draft state directly within a strict mode creation. ```typescript import { create, unsafe } from '../index'; class Foobar { bar = 1; } const baseState = { foobar: new Foobar() }; const state = create( baseState, (draft) => { unsafe(() => { draft.foobar.bar = 2; }); }, { strict: true, } ); expect(state).toBe(baseState); expect(state.foobar).toBe(baseState.foobar); expect(state.foobar.bar).toBe(2); ``` -------------------------------- ### Build Source: https://github.com/unadlib/mutative/blob/main/website/README.md Generates static website content into the 'build' directory. ```bash $ yarn build ``` -------------------------------- ### Deployment (Using SSH) Source: https://github.com/unadlib/mutative/blob/main/website/README.md Deploys the website using SSH. ```bash $ USE_SSH=true yarn deploy ``` -------------------------------- ### Development Workflow Commands Source: https://github.com/unadlib/mutative/blob/main/website/docs/extra-topics/contributing.md Commands to set up the development environment, run tests, and commit changes. ```bash yarn install yarn prettier yarn test --watch yarn commit ``` -------------------------------- ### current(target) Source: https://github.com/unadlib/mutative/blob/main/docs/functions/current.md Get current state in the draft mutation function. ```typescript import { create, current } from '../index'; const baseState = { foo: { bar: 'str' }, arr: [] }; const state = create( baseState, (draft) => { draft.foo.bar = 'str2'; expect(current(draft.foo)).toEqual({ bar: 'str2' }); }, ); ``` -------------------------------- ### arrayLengthAssignment - default: true Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/pathes.md Example demonstrating the behavior of arrayLengthAssignment when set to true. ```typescript const data = { list: [1, 2, 3] }; const [state, patches, inversePatches] = create( data, (draft) => { draft.list.length = 0; }, { enablePatches: { pathAsArray: true, arrayLengthAssignment: false, }, } ); expect(state).toMatchInlineSnapshot(` { "list": [], } `); expect(patches).toMatchInlineSnapshot(` [ { "op": "remove", "path": [ "list", 2, ], }, { "op": "remove", "path": [ "list", 1, ], }, { "op": "remove", "path": [ "list", 0, ], }, ] `); expect(inversePatches).toMatchInlineSnapshot(` [ { "op": "add", "path": [ "list", 0, ], "value": 1, }, { "op": "add", "path": [ "list", 1, ], "value": 2, }, { "op": "add", "path": [ "list", 2, ], "value": 3, }, ] `); ``` -------------------------------- ### Benchmark results summary Source: https://github.com/unadlib/mutative/blob/main/website/blog/releases/1.0/index.md Performance comparison between Mutative and Immer across different configurations (No Freeze, Freeze, Patches). ```text Naive handcrafted reducer - No Freeze x 4,777 ops/sec ±1.06% (94 runs sampled) Mutative - No Freeze x 6,783 ops/sec ±0.71% (96 runs sampled) Immer - No Freeze x 5.72 ops/sec ±0.39% (19 runs sampled) Mutative - Freeze x 1,069 ops/sec ±0.75% (97 runs sampled) Immer - Freeze x 392 ops/sec ±0.66% (92 runs sampled) Mutative - Patches and No Freeze x 1,006 ops/sec ±1.73% (95 runs sampled) Immer - Patches and No Freeze x 5.73 ops/sec ±0.16% (19 runs sampled) Mutative - Patches and Freeze x 548 ops/sec ±1.06% (94 runs sampled) Immer - Patches and Freeze x 287 ops/sec ±0.84% (93 runs sampled) The fastest method is Mutative - No Freeze ``` -------------------------------- ### Mutative reducer for object update Source: https://github.com/unadlib/mutative/blob/main/website/blog/releases/1.0/index.md Example of using Mutative to update an object immutably. ```typescript const state = create(baseState, (draft) => { draft.key0.value = i; }); ``` -------------------------------- ### Mutative reducer for array update Source: https://github.com/unadlib/mutative/blob/main/website/blog/releases/1.0/index.md Example of using Mutative to update an array immutably. ```typescript const state = create(baseState, (draft) => { draft[0].value = i; }); ``` -------------------------------- ### Reducer by object - Naive handcrafted reducer Source: https://github.com/unadlib/mutative/blob/main/website/docs/getting-started/performance.md Example of a naive handcrafted reducer for updating an immutable object. ```typescript // baseState type: Record const state = { ...baseState, key0: { ...baseState.key0, value: i, }, }; ``` -------------------------------- ### Basic Usage of apply() with patches Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/apply.md Demonstrates how to use the apply() function to re-apply patches generated by create() to obtain the new state, and how to use inverse patches to revert to the previous state. ```typescript import { create, apply } from 'mutative'; const baseState = { foo: 'bar', list: [{ text: 'todo' }], }; const [state, patches, inversePatches] = create( baseState, (draft) => { draft.foo = 'foobar'; draft.list.push({ text: 'learning' }); }, { enablePatches: true, } ); // you can apply patches to get the new state const nextState = apply(baseState, patches); expect(nextState).toEqual(state); const prevState = apply(state, inversePatches); expect(prevState).toEqual(baseState); ``` -------------------------------- ### isDraftable Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/isdraftable.md Demonstrates how to use the isDraftable() function to check if a value is draftable. ```typescript const baseState = { date: new Date(), list: [{ text: 'todo' }], }; expect(isDraftable(baseState.date)).toBeFalsy(); expect(isDraftable(baseState.list)).toBeTruthy(); ``` -------------------------------- ### Deployment (Not Using SSH) Source: https://github.com/unadlib/mutative/blob/main/website/README.md Deploys the website without using SSH, specifying the GitHub username. ```bash $ GIT_USER= yarn deploy ``` -------------------------------- ### Enable Patches Source: https://github.com/unadlib/mutative/blob/main/website/docs/advanced-guides/currying.md Demonstrates enabling patches for state updates, showing the resulting state, patches, and inverse patches. ```typescript const baseState = { foobar: { foo: 'str', bar: 'str' }, baz: { text: 'str' }, }; const [draft, finalize] = create(baseState, { enablePatches: true }); draft.foobar.bar = 'baz'; const [state, patches, inversePatches] = finalize(); expect(state).toEqual(expectedResult); expect(state).not.toBe(baseState); expect(state.foobar).not.toBe(baseState.foobar); expect(state.baz).toBe(baseState.baz); expect(patches).toEqual([ { op: 'replace', path: ['foobar', 'bar'], value: 'baz', }, ]); expect(inversePatches).toEqual([ { op: 'replace', path: ['foobar', 'bar'], value: 'str', }, ]); ``` -------------------------------- ### isDraft() Usage Example Source: https://github.com/unadlib/mutative/blob/main/website/docs/api-reference/isdraft.md Demonstrates how to use the isDraft() function to check if a value is a draft. ```typescript const baseState = { date: new Date(), list: [{ text: 'todo' }], }; const state = create(baseState, (draft) => { expect(isDraft(draft.date)).toBeFalsy(); expect(isDraft(draft.list)).toBeTruthy(); }); ```