Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Immer modifies readonly properties of nested instances that are not immerable #1148

Open
marco-eckstein opened this issue Oct 14, 2024 · 0 comments

Comments

@marco-eckstein
Copy link

🐛 Bug Report

immer allows modification of readonly properties of nested class instances that are not marked as immerable. This seems dangerous to me. Just like immer does not allow direct modification of class instances that are not marked as immerable, an exception should be thrown. Even better, the types should not allow this.

import { immerable, produce } from "immer";

class Address {
  constructor(public readonly streetName: string) {
    this.streetName = streetName;
  }
}

class ImmerableAddress {
  [immerable] = true;

  constructor(public readonly streetName: string) {
    this.streetName = streetName;
  }
}

class ImmerablePerson {
  [immerable] = true;

  constructor(public readonly address: Address) {
    this.address = address;
  }
}

describe("immer", () => {
  const immerableAddress = new ImmerableAddress("foo");
  it("works fine with immerable nested class instance", () => {
    const produced = produce(new ImmerablePerson(immerableAddress), (draft) => {
      draft.address.streetName = "bar";
    });
    expect(produced.address.streetName).toBe("bar");
    expect(produced.address).toBeInstanceOf(ImmerableAddress);
    expect(produced.address).not.toBe(immerableAddress);
  });

  const address = new Address("foo");
  it("allows illegal modification of non-immerable nested class instance", () => {
    const produced = produce(new ImmerablePerson(address), (draft) => {
      draft.address.streetName = "bar"; // works unexpectedly
    });
    expect(produced.address.streetName).toBe("bar");
    expect(produced.address).toBeInstanceOf(Address);
    expect(produced.address).toBe(address);
  });
});

Link to repro

CodeSandbox demo

Environment

Immer 10.1.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant