From 47aebfebb152c5dd741b97d8cc7d539f11e03792 Mon Sep 17 00:00:00 2001 From: unadlib Date: Sun, 11 Oct 2026 21:56:46 +0800 Subject: [PATCH 1/3] fix: type a curried recipe whose draft is annotated with a type parameter --- src/makeCreator.ts | 12 ++++++++++++ test/types.test.ts | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/makeCreator.ts b/src/makeCreator.ts index 0b595999..e00989de 100644 --- a/src/makeCreator.ts +++ b/src/makeCreator.ts @@ -169,6 +169,18 @@ type ExplicitPrimitiveRecipe = mutate: (draft: Draft, ...args: P) => R, options?: ExternalOptions ): (base: T, ...args: P) => CreateResult; + // A recipe that annotates its draft with the state type itself, such as a + // type parameter, which TypeScript cannot match against `Draft`. + < + T extends any, + P extends any[] = [], + F extends boolean = _F, + O extends PatchesOptions = _O, + R extends void | Promise | T | Promise = void, + >( + mutate: (draft: T, ...args: P) => R, + options?: ExternalOptions + ): (base: T, ...args: P) => CreateResult; ( base: T, options?: ExternalOptions diff --git a/test/types.test.ts b/test/types.test.ts index f73cd72f..902d9e45 100644 --- a/test/types.test.ts +++ b/test/types.test.ts @@ -373,6 +373,40 @@ test('a curried recipe with an annotated draft can return a new state', async () expect(mutate(base()).count).toBe(2); }); +test('a curried recipe whose draft is a type parameter gives a producer', async () => { + function increment() { + return create((draft: T) => { + draft.count += 1; + }); + } + function incrementLater() { + return create(async (draft: T) => { + draft.count += 1; + }); + } + function incrementBy() { + return create((draft: T, by: number) => { + draft.count += by; + }); + } + function reset() { + return create((draft: T) => ({ ...draft, count: 0 })); + } + + expectTypeOf(increment()).toEqualTypeOf<(base: State) => State>(); + expect(increment()(base()).count).toBe(2); + expectTypeOf(incrementLater()).toEqualTypeOf< + (base: State) => Promise + >(); + expect((await incrementLater()(base())).count).toBe(2); + expectTypeOf(incrementBy()).toEqualTypeOf< + (base: State, by: number) => State + >(); + expect(incrementBy()(base(), 2).count).toBe(3); + expectTypeOf(reset()).toEqualTypeOf<(base: State) => State>(); + expect(reset()(base())).toEqual({ count: 0, list: [1] }); +}); + test('generic helpers keep synchronous replacement results', () => { function update(state: T, recipe: (draft: T) => T): T { return create(state, recipe); From cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9 Mon Sep 17 00:00:00 2001 From: unadlib Date: Sun, 11 Oct 2026 21:56:56 +0800 Subject: [PATCH 2/3] docs: describe curried recipes whose draft is annotated with a type parameter --- README.md | 4 ++-- website/content/docs/advanced-guides/migration-v2.mdx | 2 +- website/content/docs/api-reference/create.mdx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4b246dae..5a77bef9 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ const state = create(baseState, (draft) => { In this basic example, the changes to the draft are 'mutative' within the draft callback, and `create()` is finally executed with a new immutable state. -The recipe can be an async function: `create()` then returns a Promise of the result, and the draft stays usable until that Promise settles. `create()` recognizes the Promises of the current JavaScript realm only, so an async function from another realm, such as a `vm` context or an iframe, needs a wrapper from this realm: `create(baseState, async (draft) => { return await recipe(draft); })`. TypeScript types the result as a Promise as well, except with an explicit state type that is a type parameter, as in `create(base, async (draft) => { … })` in a generic function, or that includes Promises, such as `object` or `unknown`, which gives the state type itself. In generic code, leave out the type argument: `create(base, async (draft) => { … })` gives `Promise`. +The recipe can be an async function: `create()` then returns a Promise of the result, and the draft stays usable until that Promise settles. `create()` recognizes the Promises of the current JavaScript realm only, so an async function from another realm, such as a `vm` context or an iframe, needs a wrapper from this realm: `create(baseState, async (draft) => { return await recipe(draft); })`. TypeScript types the result as a Promise as well, except with an explicit state type that is a type parameter, as in `create(base, async (draft) => { … })` in a generic function, or that includes Promises, such as `object` or `unknown`, which gives the state type itself. In generic code, leave out the type argument: `create(base, async (draft) => { … })` gives `Promise`, and `create(async (draft: T) => { … })` gives `(base: T) => Promise`. #### `create(state, fn, options)` @@ -806,7 +806,7 @@ Mutative v2 keeps the v1 API. The changes below, made since v1.3.0, can affect e - `create()` with an explicit state type and an async recipe, such as `create(base, async (draft) => { … })`, returns `Promise`, and so do curried producers; v1 typed the result as `State`. A state type that is a type parameter, as in a generic function, or that includes Promises, such as `object` or `unknown`, still gives the state type for async recipes and for recipes that may return a Promise, as in v1; leave out the type argument in generic code. - `apply()` accepts `enableAutoFreeze: true` and then returns `Immutable`, as `apply()` does; v1 rejected the option and typed the frozen result as mutable. With `enableAutoFreeze` typed as `boolean` or optional `true`, the result is `State | Immutable`. With `mutable` typed as `boolean`, optional `boolean`, or optional `true`, `apply()` returns `State | void`. -- A curried producer whose recipe annotates its draft and returns a new state, such as `create((draft: State) => ({ ...draft, count: 0 }))`, returns `State`, or `Promise` for an async recipe. v1 typed such a call as a manual draft, so calling the producer did not compile. +- A curried producer whose recipe annotates its draft and returns a new state, such as `create((draft: State) => ({ ...draft, count: 0 }))`, returns `State`, or `Promise` for an async recipe. v1 typed such a call as a manual draft, so calling the producer did not compile. A recipe whose draft is annotated with a type parameter, as in `create((draft: T) => { … })` in a generic function, also gives a producer, which v1 typed as a manual draft as well. - With an explicit state type, a recipe that may or may not return a Promise, such as one typed `(draft: State) => void | Promise`, gives `State | Promise`, also for a primitive state type, such as `number`, and in curried producers and creators from `makeCreator()`. v1 typed the result as `State`. ### Fixes that change results diff --git a/website/content/docs/advanced-guides/migration-v2.mdx b/website/content/docs/advanced-guides/migration-v2.mdx index 1a169923..8ab88830 100644 --- a/website/content/docs/advanced-guides/migration-v2.mdx +++ b/website/content/docs/advanced-guides/migration-v2.mdx @@ -42,7 +42,7 @@ Mutative v2 keeps the v1 API. The changes below, made since v1.3.0, can affect e - `create()` with an explicit state type and an async recipe, such as `create(base, async (draft) => { … })`, returns `Promise`, and so do curried producers; v1 typed the result as `State`. A state type that is a type parameter, as in a generic function, or that includes Promises, such as `object` or `unknown`, still gives the state type for async recipes and for recipes that may return a Promise, as in v1; leave out the type argument in generic code. - `apply()` accepts `enableAutoFreeze: true` and then returns `Immutable`, as `apply()` does; v1 rejected the option and typed the frozen result as mutable. With `enableAutoFreeze` typed as `boolean` or optional `true`, the result is `State | Immutable`. With `mutable` typed as `boolean`, optional `boolean`, or optional `true`, `apply()` returns `State | void`. -- A curried producer whose recipe annotates its draft and returns a new state, such as `create((draft: State) => ({ ...draft, count: 0 }))`, returns `State`, or `Promise` for an async recipe. v1 typed such a call as a manual draft, so calling the producer did not compile. +- A curried producer whose recipe annotates its draft and returns a new state, such as `create((draft: State) => ({ ...draft, count: 0 }))`, returns `State`, or `Promise` for an async recipe. v1 typed such a call as a manual draft, so calling the producer did not compile. A recipe whose draft is annotated with a type parameter, as in `create((draft: T) => { … })` in a generic function, also gives a producer, which v1 typed as a manual draft as well. - With an explicit state type, a recipe that may or may not return a Promise, such as one typed `(draft: State) => void | Promise`, gives `State | Promise`, also for a primitive state type, such as `number`, and in curried producers and creators from `makeCreator()`. v1 typed the result as `State`. ## Fixes that change results diff --git a/website/content/docs/api-reference/create.mdx b/website/content/docs/api-reference/create.mdx index 64c36f7e..8ce60de5 100644 --- a/website/content/docs/api-reference/create.mdx +++ b/website/content/docs/api-reference/create.mdx @@ -22,7 +22,7 @@ const state = create(baseState, (draft) => { In this basic example, the changes to the draft are 'mutative' within the draft callback, and `create()` is finally executed with a new immutable state. -The recipe can be an async function: `create()` then returns a Promise of the result, and the draft stays usable until that Promise settles. `create()` recognizes the Promises of the current JavaScript realm only, so an async function from another realm, such as a `vm` context or an iframe, needs a wrapper from this realm: `create(baseState, async (draft) => { return await recipe(draft); })`. TypeScript types the result as a Promise as well, except with an explicit state type that is a type parameter, as in `create(base, async (draft) => { … })` in a generic function, or that includes Promises, such as `object` or `unknown`, which gives the state type itself. In generic code, leave out the type argument: `create(base, async (draft) => { … })` gives `Promise`. +The recipe can be an async function: `create()` then returns a Promise of the result, and the draft stays usable until that Promise settles. `create()` recognizes the Promises of the current JavaScript realm only, so an async function from another realm, such as a `vm` context or an iframe, needs a wrapper from this realm: `create(baseState, async (draft) => { return await recipe(draft); })`. TypeScript types the result as a Promise as well, except with an explicit state type that is a type parameter, as in `create(base, async (draft) => { … })` in a generic function, or that includes Promises, such as `object` or `unknown`, which gives the state type itself. In generic code, leave out the type argument: `create(base, async (draft) => { … })` gives `Promise`, and `create(async (draft: T) => { … })` gives `(base: T) => Promise`. ## create(state, fn, options) - options From 9562f608c44e9cd9b5976a19d29737dd27d46bd3 Mon Sep 17 00:00:00 2001 From: unadlib Date: Sun, 11 Oct 2026 21:57:12 +0800 Subject: [PATCH 3/3] docs: regenerate the API reference --- docs/functions/apply.md | 10 ++--- docs/functions/castDraft.md | 2 +- docs/functions/castImmutable.md | 2 +- docs/functions/castMutable.md | 2 +- docs/functions/current.md | 4 +- docs/functions/isDraft.md | 2 +- docs/functions/isDraftable.md | 2 +- docs/functions/markSimpleObject.md | 2 +- docs/functions/original.md | 2 +- docs/functions/rawReturn.md | 2 +- docs/functions/unsafe.md | 2 +- docs/interfaces/Options.md | 10 ++--- docs/type-aliases/Draft.md | 2 +- docs/type-aliases/DraftedObject.md | 2 +- docs/type-aliases/Immutable.md | 2 +- docs/type-aliases/Patch.md | 2 +- docs/type-aliases/Patches.md | 2 +- docs/type-aliases/PatchesOptions.md | 2 +- docs/variables/create.md | 58 ++++++++++++++++++++++++++++- docs/variables/makeCreator.md | 56 +++++++++++++++++++++++++++- 20 files changed, 137 insertions(+), 31 deletions(-) diff --git a/docs/functions/apply.md b/docs/functions/apply.md index ca92da5d..f3cec623 100644 --- a/docs/functions/apply.md +++ b/docs/functions/apply.md @@ -10,7 +10,7 @@ > **apply**\<`T`, `F`, `_A`\>(`state`, `patches`, `applyOptions?`): `ApplyState`\<`T`, `F`, `undefined`\> -Defined in: [apply.ts:63](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/apply.ts#L63) +Defined in: [apply.ts:63](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/apply.ts#L63) `apply(state, patches)` to apply patches to state @@ -68,7 +68,7 @@ expect(state).toEqual(apply(baseState, patches)); > **apply**\<`T`, `F`, `A`\>(`state`, `patches`, `applyOptions`): `ApplyResult`\<`T`, `F`, `A`\> -Defined in: [apply.ts:72](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/apply.ts#L72) +Defined in: [apply.ts:72](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/apply.ts#L72) `apply(state, patches)` to apply patches to state @@ -126,7 +126,7 @@ expect(state).toEqual(apply(baseState, patches)); > **apply**\<`T`, `F`, `A`\>(`state`, `patches`, `applyOptions?`): `ApplyResult`\<`T`, `F`, `undefined` \| `A`\> -Defined in: [apply.ts:79](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/apply.ts#L79) +Defined in: [apply.ts:79](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/apply.ts#L79) `apply(state, patches)` to apply patches to state @@ -184,7 +184,7 @@ expect(state).toEqual(apply(baseState, patches)); > **apply**\<`T`, `F`\>(`state`, `patches`, `applyOptions`): `void` -Defined in: [apply.ts:90](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/apply.ts#L90) +Defined in: [apply.ts:90](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/apply.ts#L90) `apply(state, patches)` to apply patches to state @@ -240,7 +240,7 @@ expect(state).toEqual(apply(baseState, patches)); > **apply**\<`T`, `F`\>(`state`, `patches`, `applyOptions`): `ApplyResult`\<`T`, `F`, `undefined` \| `ApplyMutableOptions`\> -Defined in: [apply.ts:95](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/apply.ts#L95) +Defined in: [apply.ts:95](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/apply.ts#L95) `apply(state, patches)` to apply patches to state diff --git a/docs/functions/castDraft.md b/docs/functions/castDraft.md index d47ff341..9273884f 100644 --- a/docs/functions/castDraft.md +++ b/docs/functions/castDraft.md @@ -8,7 +8,7 @@ > **castDraft**\<`T`\>(`value`): [`Draft`](../type-aliases/Draft.md)\<`T`\> -Defined in: [utils/cast.ts:6](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/cast.ts#L6) +Defined in: [utils/cast.ts:6](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/cast.ts#L6) Cast a value to an Draft type value. diff --git a/docs/functions/castImmutable.md b/docs/functions/castImmutable.md index 1fa5a2c4..be10040b 100644 --- a/docs/functions/castImmutable.md +++ b/docs/functions/castImmutable.md @@ -8,7 +8,7 @@ > **castImmutable**\<`T`\>(`value`): [`Immutable`](../type-aliases/Immutable.md)\<`T`\> -Defined in: [utils/cast.ts:13](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/cast.ts#L13) +Defined in: [utils/cast.ts:13](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/cast.ts#L13) Cast a value to an Immutable type value. diff --git a/docs/functions/castMutable.md b/docs/functions/castMutable.md index f67bd5ea..865851e1 100644 --- a/docs/functions/castMutable.md +++ b/docs/functions/castMutable.md @@ -8,7 +8,7 @@ > **castMutable**\<`T`\>(`draft`): `T` -Defined in: [utils/cast.ts:20](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/cast.ts#L20) +Defined in: [utils/cast.ts:20](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/cast.ts#L20) Cast a value to an Mutable type value. diff --git a/docs/functions/current.md b/docs/functions/current.md index 9e2a5dc6..df16a540 100644 --- a/docs/functions/current.md +++ b/docs/functions/current.md @@ -10,7 +10,7 @@ > **current**\<`T`\>(`target`): `T` -Defined in: [current.ts:198](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/current.ts#L198) +Defined in: [current.ts:198](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/current.ts#L198) `current(draft)` to get current state in the draft mutation function. @@ -49,7 +49,7 @@ const state = create( > **current**\<`T`\>(`target`): `T` -Defined in: [current.ts:200](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/current.ts#L200) +Defined in: [current.ts:200](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/current.ts#L200) ### Type Parameters diff --git a/docs/functions/isDraft.md b/docs/functions/isDraft.md index 85244467..8276b35a 100644 --- a/docs/functions/isDraft.md +++ b/docs/functions/isDraft.md @@ -8,7 +8,7 @@ > **isDraft**(`target`): `boolean` -Defined in: [utils/draft.ts:33](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/draft.ts#L33) +Defined in: [utils/draft.ts:33](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/draft.ts#L33) Check if the value is a draft diff --git a/docs/functions/isDraftable.md b/docs/functions/isDraftable.md index b86ce06e..e8e9c82a 100644 --- a/docs/functions/isDraftable.md +++ b/docs/functions/isDraftable.md @@ -8,7 +8,7 @@ > **isDraftable**(`value`, `options?`): `boolean` -Defined in: [utils/draft.ts:59](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/draft.ts#L59) +Defined in: [utils/draft.ts:59](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/draft.ts#L59) Check if a value is draftable diff --git a/docs/functions/markSimpleObject.md b/docs/functions/markSimpleObject.md index e0a98ad2..73bd305d 100644 --- a/docs/functions/markSimpleObject.md +++ b/docs/functions/markSimpleObject.md @@ -8,7 +8,7 @@ > **markSimpleObject**(`value`): `undefined` \| `"immutable"` -Defined in: [utils/marker.ts:26](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/utils/marker.ts#L26) +Defined in: [utils/marker.ts:26](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/utils/marker.ts#L26) ## Parameters diff --git a/docs/functions/original.md b/docs/functions/original.md index 23b09202..41ecf031 100644 --- a/docs/functions/original.md +++ b/docs/functions/original.md @@ -8,7 +8,7 @@ > **original**\<`T`\>(`target`): `T` -Defined in: [original.ts:22](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/original.ts#L22) +Defined in: [original.ts:22](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/original.ts#L22) `original(draft)` to get original state in the draft mutation function. diff --git a/docs/functions/rawReturn.md b/docs/functions/rawReturn.md index 3b553837..9e48afcc 100644 --- a/docs/functions/rawReturn.md +++ b/docs/functions/rawReturn.md @@ -8,7 +8,7 @@ > **rawReturn**\<`T`\>(`value`): `T` -Defined in: [rawReturn.ts:22](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/rawReturn.ts#L22) +Defined in: [rawReturn.ts:22](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/rawReturn.ts#L22) Use rawReturn() to wrap the return value to skip the draft check and thus improve performance. diff --git a/docs/functions/unsafe.md b/docs/functions/unsafe.md index 744abe38..fe01afe8 100644 --- a/docs/functions/unsafe.md +++ b/docs/functions/unsafe.md @@ -8,7 +8,7 @@ > **unsafe**\<`T`\>(`callback`): `T` -Defined in: [unsafe.ts:57](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/unsafe.ts#L57) +Defined in: [unsafe.ts:57](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/unsafe.ts#L57) `unsafe(callback)` to access mutable data directly in strict mode. diff --git a/docs/interfaces/Options.md b/docs/interfaces/Options.md index 6f991125..fe227ee7 100644 --- a/docs/interfaces/Options.md +++ b/docs/interfaces/Options.md @@ -6,7 +6,7 @@ # Interface: Options\ -Defined in: [interface.ts:171](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L171) +Defined in: [interface.ts:171](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L171) ## Type Parameters @@ -24,7 +24,7 @@ Defined in: [interface.ts:171](https://github.com/unadlib/mutative/blob/c2e96282 > `optional` **enableAutoFreeze**: `F` -Defined in: [interface.ts:184](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L184) +Defined in: [interface.ts:184](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L184) Enable autoFreeze, and return frozen state. @@ -34,7 +34,7 @@ Enable autoFreeze, and return frozen state. > `optional` **enablePatches**: `O` -Defined in: [interface.ts:180](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L180) +Defined in: [interface.ts:180](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L180) Enable patch, and return the patches and inversePatches. @@ -44,7 +44,7 @@ Enable patch, and return the patches and inversePatches. > `optional` **mark**: `Mark`\<`O`, `F`\> \| `Mark`\<`O`, `F`\>[] -Defined in: [interface.ts:189](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L189) +Defined in: [interface.ts:189](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L189) Set a mark to determine if the object is mutable or if an instance is an immutable. And it can also return a shallow copy function(AutoFreeze and Patches should both be disabled). @@ -55,7 +55,7 @@ And it can also return a shallow copy function(AutoFreeze and Patches should bot > `optional` **strict**: `boolean` -Defined in: [interface.ts:176](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L176) +Defined in: [interface.ts:176](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L176) In strict mode, Forbid accessing non-draftable values and forbid returning a non-draft value. Development builds also warn once when a recipe leaves 1,000 or more drafts unchanged. diff --git a/docs/type-aliases/Draft.md b/docs/type-aliases/Draft.md index 8ee6a403..e9a77d4c 100644 --- a/docs/type-aliases/Draft.md +++ b/docs/type-aliases/Draft.md @@ -8,7 +8,7 @@ > **Draft**\<`T`\> = `T` *extends* `Primitive` \| `AtomicObject` ? `T` : `T` *extends* `IfAvailable`\<`ReadonlyMap`\\> ? `DraftedMap`\<`K`, `V`\> : `T` *extends* `IfAvailable`\<`ReadonlySet`\\> ? `DraftedSet`\<`V`\> : `T` *extends* `WeakReferences` ? `T` : `T` *extends* `object` ? [`DraftedObject`](DraftedObject.md)\<`T`\> : `T` -Defined in: [interface.ts:229](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L229) +Defined in: [interface.ts:229](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L229) ## Type Parameters diff --git a/docs/type-aliases/DraftedObject.md b/docs/type-aliases/DraftedObject.md index 1a902141..557b07f5 100644 --- a/docs/type-aliases/DraftedObject.md +++ b/docs/type-aliases/DraftedObject.md @@ -8,7 +8,7 @@ > **DraftedObject**\<`T`\> = `{ -readonly [K in keyof T]: Draft }` -Defined in: [interface.ts:225](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L225) +Defined in: [interface.ts:225](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L225) ## Type Parameters diff --git a/docs/type-aliases/Immutable.md b/docs/type-aliases/Immutable.md index b661bfd5..ab2a190c 100644 --- a/docs/type-aliases/Immutable.md +++ b/docs/type-aliases/Immutable.md @@ -8,7 +8,7 @@ > **Immutable**\<`T`\> = `T` *extends* `Primitive` \| `AtomicObject` ? `T` : `T` *extends* `IfAvailable`\<`ReadonlyMap`\\> ? `ImmutableMap`\<`K`, `V`\> : `T` *extends* `IfAvailable`\<`ReadonlySet`\\> ? `ImmutableSet`\<`V`\> : `T` *extends* `WeakReferences` ? `T` : `T` *extends* `object` ? `ImmutableObject`\<`T`\> : `T` -Defined in: [interface.ts:211](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L211) +Defined in: [interface.ts:211](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L211) ## Type Parameters diff --git a/docs/type-aliases/Patch.md b/docs/type-aliases/Patch.md index 822a8251..40dd346e 100644 --- a/docs/type-aliases/Patch.md +++ b/docs/type-aliases/Patch.md @@ -8,7 +8,7 @@ > **Patch**\<`P`\> = `P` *extends* `object` ? `IPatch` & `object` : `P` *extends* `true` \| `object` ? `IPatch` & `object` : `IPatch` & `object` -Defined in: [interface.ts:96](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L96) +Defined in: [interface.ts:96](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L96) ## Type Parameters diff --git a/docs/type-aliases/Patches.md b/docs/type-aliases/Patches.md index c773da83..8a1c7a6e 100644 --- a/docs/type-aliases/Patches.md +++ b/docs/type-aliases/Patches.md @@ -8,7 +8,7 @@ > **Patches**\<`P`\> = [`Patch`](Patch.md)\<`P`\>[] -Defined in: [interface.ts:110](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L110) +Defined in: [interface.ts:110](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L110) ## Type Parameters diff --git a/docs/type-aliases/PatchesOptions.md b/docs/type-aliases/PatchesOptions.md index 2a10b555..06f1f52d 100644 --- a/docs/type-aliases/PatchesOptions.md +++ b/docs/type-aliases/PatchesOptions.md @@ -8,7 +8,7 @@ > **PatchesOptions** = `boolean` \| \{ `arrayLengthAssignment?`: `boolean`; `pathAsArray?`: `boolean`; \} -Defined in: [interface.ts:18](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/interface.ts#L18) +Defined in: [interface.ts:18](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/interface.ts#L18) ## Type Declaration diff --git a/docs/variables/create.md b/docs/variables/create.md index 303e5a67..2fe2406f 100644 --- a/docs/variables/create.md +++ b/docs/variables/create.md @@ -6,9 +6,9 @@ # Variable: create() -> `const` **create**: \{\<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\]; \} +> `const` **create**: \{\<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\]; \} -Defined in: [create.ts:25](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/create.ts#L25) +Defined in: [create.ts:25](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/create.ts#L25) `create(baseState, callback, options)` to create the next state @@ -511,6 +511,60 @@ expect(state.arr).toBe(baseState.arr); ## Call Signature +> \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\> + +### Type Parameters + +#### T + +`T` *extends* `unknown` + +#### P + +`P` *extends* `any`[] = \[\] + +#### F + +`F` *extends* `boolean` = `false` + +#### O + +`O` *extends* [`PatchesOptions`](../type-aliases/PatchesOptions.md) = `false` + +#### R + +`R` *extends* `unknown` = `void` + +### Parameters + +#### mutate + +(`draft`, ...`args`) => `R` + +#### options? + +[`Options`](../interfaces/Options.md)\<`O`, `F`\> + +### Returns + +> (`base`, ...`args`): `CreateResult`\<`T`, `O`, `F`, `R`\> + +#### Parameters + +##### base + +`T` + +##### args + +...`P` + +#### Returns + +`CreateResult`\<`T`, `O`, `F`, `R`\> + +## Call Signature + > \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\] ### Type Parameters diff --git a/docs/variables/makeCreator.md b/docs/variables/makeCreator.md index bf3ddddd..f1776d87 100644 --- a/docs/variables/makeCreator.md +++ b/docs/variables/makeCreator.md @@ -6,9 +6,9 @@ # Variable: makeCreator() -> `const` **makeCreator**: \<`_F`, `_O`\>(`options?`) => \{\<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\]; \} +> `const` **makeCreator**: \<`_F`, `_O`\>(`options?`) => \{\<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `F`, `O`\>(`base`, `mutate`, `options?`): `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `F`, `O`, `R`\>(`base`, `mutate`, `options?`): `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>; \<`T`, `P`, `F`, `O`\>(`mutate`, `options?`): (`base`, ...`args`) => `Result`\<`ExplicitState`\<`T`\>, `O`, `F`\> \| `Promise`\<`Result`\<`ExplicitState`\<`T`\>, `O`, `F`\>\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\>; \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\]; \} -Defined in: [makeCreator.ts:205](https://github.com/unadlib/mutative/blob/c2e96282fb77355d4c5f83d86c6d201dee734d45/src/makeCreator.ts#L205) +Defined in: [makeCreator.ts:217](https://github.com/unadlib/mutative/blob/cbcd06102ce38252b6fa8b2c9f28a18ba9d9fbe9/src/makeCreator.ts#L217) `makeCreator(options)` to make a creator function. @@ -507,6 +507,58 @@ expect(Object.isFrozen(state)).toBeTruthy(); `CreateResult`\<`T`, `O`, `F`, `R`\> +> \<`T`, `P`, `F`, `O`, `R`\>(`mutate`, `options?`): (`base`, ...`args`) => `CreateResult`\<`T`, `O`, `F`, `R`\> + +### Type Parameters + +#### T + +`T` *extends* `unknown` + +#### P + +`P` *extends* `any`[] = \[\] + +#### F + +`F` *extends* `boolean` = `_F` + +#### O + +`O` *extends* [`PatchesOptions`](../type-aliases/PatchesOptions.md) = `_O` + +#### R + +`R` *extends* `unknown` = `void` + +### Parameters + +#### mutate + +(`draft`, ...`args`) => `R` + +#### options? + +[`Options`](../interfaces/Options.md)\<`O`, `F`\> + +### Returns + +> (`base`, ...`args`): `CreateResult`\<`T`, `O`, `F`, `R`\> + +#### Parameters + +##### base + +`T` + +##### args + +...`P` + +#### Returns + +`CreateResult`\<`T`, `O`, `F`, `R`\> + > \<`T`, `O`, `F`\>(`base`, `options?`): \[[`Draft`](../type-aliases/Draft.md)\<`T`\>, () => `Result`\<`T`, `O`, `F`\>\] ### Type Parameters