From 45b079974579c3be0d1eef83093b3d07e864e1d0 Mon Sep 17 00:00:00 2001 From: Alexander Kireev Date: Thu, 11 Jun 2026 03:24:55 +0700 Subject: [PATCH] fix: correct curried produceWithPatches return type The curried forms of produceWithPatches inferred the wrong type: - produceWithPatches(recipe) returned the draft type (WritableDraft) in the result tuple instead of the original State - the explicit-generic form produceWithPatches(recipe) resolved to never and was not callable IProduceWithPatches was missing the curried overloads that IProduce already has. Mirror those overloads, wrapped in PatchesTuple, so the curried produceWithPatches infers the same state type as produce. Closes #1045 --- __tests__/produce.ts | 35 +++++++++++++++++++++++++++++++++++ src/types/types-external.ts | 16 ++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/__tests__/produce.ts b/__tests__/produce.ts index 912c9fea..357daaf2 100644 --- a/__tests__/produce.ts +++ b/__tests__/produce.ts @@ -755,6 +755,41 @@ it("infers curried", () => { }) assert(f, _ as (state: ROState) => ROState) } + // produceWithPatches should infer the same state type as produce (#1045), + // just wrapped in the [state, patches, inversePatches] tuple + { + // curried + const f = produceWithPatches((state: State) => { + state.count++ + }) + assert( + f, + _ as (state: Immutable) => readonly [State, Patch[], Patch[]] + ) + } + { + // curried, with extra argument + const f = produceWithPatches((state: State, delta: number) => { + state.count += delta + }) + assert( + f, + _ as ( + state: Immutable, + delta: number + ) => readonly [State, Patch[], Patch[]] + ) + } + { + // explicitly use generic, but curried + const f = produceWithPatches((state, delta) => { + state.count += delta + }) + assert( + f, + _ as (state: State, delta: number) => readonly [State, Patch[], Patch[]] + ) + } } it("allows for mixed property value types", () => { diff --git a/src/types/types-external.ts b/src/types/types-external.ts index 8c8fedd9..d42ab8f2 100644 --- a/src/types/types-external.ts +++ b/src/types/types-external.ts @@ -234,6 +234,22 @@ export interface IProduce { export interface IProduceWithPatches { // Types copied from IProduce, wrapped with PatchesTuple (recipe: Recipe): InferCurriedFromRecipe + + /** Curried producer that infers curried from the State generic, which is explicitly passed in. */ + ( + recipe: ( + state: Draft, + ...args: Args + ) => ValidRecipeReturnType, + initialState: State + ): (state?: State, ...args: Args) => PatchesTuple + ( + recipe: (state: Draft) => ValidRecipeReturnType + ): (state: State) => PatchesTuple + ( + recipe: (state: Draft, ...args: Args) => ValidRecipeReturnType + ): (state: State, ...args: Args) => PatchesTuple + ( recipe: Recipe, initialState: State