Immer modifies `readonly` properties of nested instances that are not immerable

Aberta
#1,148 0 comentários 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 4 dias

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
35/100
Tipo de issue
Bug
Clareza
Precisa de esclarecimento
Status de atividade
Estagnada
Stack de tecnologia
javascript, typescript
Domínio
tooling

Direção de pesquisa

Comece pela reprodução vinculada no CodeSandbox e inspecione o tratamento existente de instâncias de classe não immerable e da tipagem readonly. Considera-se concluído quando o caso Address aninhado for rejeitado de forma consistente, com cobertura de regressão para o comportamento em runtime e/ou de tipos; a issue não escolhe entre esses resultados.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

🐛 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

Linguagem predominante
JavaScript
Estrelas
29k
Forks
905
Merge médio
3d 16h
PRs com merge (30d)
22

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de immerjs/immer

Todas as issues de immerjs/immer

Issues semelhantes

Mais issues de JavaScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.