diff --git a/__tests__/empty.ts b/__tests__/empty.ts index 798114d7..10295f8e 100644 --- a/__tests__/empty.ts +++ b/__tests__/empty.ts @@ -2,9 +2,11 @@ import { produce, produceWithPatches, setUseProxies, - enableAllPlugins + enableAllPlugins, + immerable, + applyPatches } from "../src/immer" -import {DRAFT_STATE} from "../src/internal" +import {DRAFT_STATE, Patch} from "../src/internal" enableAllPlugins() @@ -149,3 +151,53 @@ function createBaseState() { } return data } + +describe("#768", () => { + class Stock { + [immerable] = true + + constructor(public price: number) {} + + pushPrice(price: number) { + this.price = price + } + } + + type State = { + stock: Stock + } + + test("bla", () => { + // Set up conditions to produce the error + const errorProducingPatch = [ + { + op: "replace", + path: ["stock"], + value: new Stock(200) + } + ] as Patch[] + + // Start with modified state + const state = { + stock: new Stock(100) + } + + expect(state.stock.price).toEqual(100) + expect(state.stock[immerable]).toBeTruthy() + // Use patch to "replace" stocks + debugger + const resetState: State = applyPatches(state, errorProducingPatch) + expect(state.stock.price).toEqual(100) + expect(resetState.stock.price).toEqual(200) + expect(resetState.stock[immerable]).toBeTruthy() + + // Problems come in when resetState is modified + const updatedState = produce(resetState, draft => { + draft.stock.pushPrice(300) + }) + expect(state.stock.price).toEqual(100) + expect(updatedState.stock.price).toEqual(300) + expect(updatedState.stock[immerable]).toBeTruthy() + expect(resetState.stock.price).toEqual(200) + }) +}) diff --git a/__tests__/tsconfig.json b/__tests__/tsconfig.json index 19c0864b..4b76f62e 100644 --- a/__tests__/tsconfig.json +++ b/__tests__/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "lib": ["es2015"], "strict": true, - "noUnusedLocals": false + "noUnusedLocals": false, + "target": "ES5" } } diff --git a/src/core/immerClass.ts b/src/core/immerClass.ts index 1818e909..a2954a16 100644 --- a/src/core/immerClass.ts +++ b/src/core/immerClass.ts @@ -185,7 +185,7 @@ export class Immer implements ProducersFns { this.useProxies_ = value } - applyPatches(base: Objectish, patches: Patch[]) { + applyPatches(base: Objectish, patches: Patch[]): T { // If a patch replaces the entire state, take that replacement as base // before applying patches let i: number @@ -200,12 +200,12 @@ export class Immer implements ProducersFns { const applyPatchesImpl = getPlugin("Patches").applyPatches_ if (isDraft(base)) { // N.B: never hits if some patch a replacement, patches are never drafts - return applyPatchesImpl(base, patches) + return applyPatchesImpl(base, patches) as any } // Otherwise, produce a copy of the base state. return this.produce(base, (draft: Drafted) => applyPatchesImpl(draft, patches.slice(i + 1)) - ) + ) as any } } diff --git a/src/plugins/patches.ts b/src/plugins/patches.ts index a06a526a..bc3ba282 100644 --- a/src/plugins/patches.ts +++ b/src/plugins/patches.ts @@ -1,3 +1,4 @@ +import {immerable} from "../immer" import { ImmerState, Patch, @@ -287,6 +288,7 @@ export function enablePatches() { if (isSet(obj)) return new Set(Array.from(obj).map(deepClonePatchValue)) const cloned = Object.create(Object.getPrototypeOf(obj)) for (const key in obj) cloned[key] = deepClonePatchValue(obj[key]) + if (has(obj, immerable)) cloned[immerable] = obj[immerable] return cloned }