This repository reproduces the issue outlined in immerjs/immer#768.
In short, I believe applying a replace
patch on certain types of state causes undesirable
behavior when the result of that patch is passed to produce
.
The error is that any subsequent updates using produce
to the result of applyPatch
will mutate
the produce
function's base
parameter, which is undesirable for an immutability library.
npm install
npm start
This repository tests 9 scenarios that test different structures of state. You can find the tests
in src/reproduce.test.ts
. I outline the basic setup of each test and their results below.
state.stocks is a map and stocks are plain objects, with patch replacing state.stocks
type State = {
stocks: Map<string, { ticker: string; name: string; priceHistory: number[] }>;
};
const errorProducingPatch = [
{
op: "replace",
path: ["stocks"],
value: makeInitialState().stocks, // Map<string, {ticker: string; name: string; priceHistory: number[]>
},
] as Patch[];
️This setup does not reproduce the issue described above.
state.stocks is a map of [immerable] classes, with patch replacing state.stocks
type State = {
stocks: Map<string, Stock>;
};
const errorProducingPatch = [
{
op: "replace",
path: ["stocks"],
value: makeInitialState().stocks, // Map<string, Stock>
},
] as Patch[];
️This setup reproduces the issue described above.
state.stocks is a map of [immerable] classes, with patch replacing state root
type State = {
stocks: Map<string, Stock>;
};
const errorProducingPatch = [
{
op: "replace",
path: [],
value: makeInitialState(), // State
},
] as Patch[];
️This setup does not reproduce the issue described above.
state.stocks is an object keying [immerable] classes, with patch replacing state.stocks
type State = {
stocks: { [key: string]: Stock };
};
const errorProducingPatch = [
{
op: "replace",
path: ["stocks"],
value: makeInitialState().stocks, // { [key: string]: Stock }
},
] as Patch[];
️This setup reproduces the issue described above.
state.stocks is an array of [immerable] classes, with patch replacing state.stocks
type State = {
stocks: Stock[];
};
const errorProducingPatch = [
{
op: "replace",
path: ["stocks"],
value: makeInitialState().stocks, // Stock[]
},
] as Patch[];
️This setup reproduces the issue described above.
state.stock is a single [immerable] class, with patch replacing state.stock
type State = {
stock: Stock;
};
const errorProducingPatch = [
{
op: "replace",
path: ["stock"],
value: makeInitialState().stock, // Stock
},
] as Patch[];
️This setup reproduces the issue described above.
state is an array of [immerable] classes, with patch replacing state[0]
type State = Stock[];
const errorProducingPatch = [
{
op: "replace",
path: [0],
value: makeInitialState()[0], // Stock
},
] as Patch[];
️This setup reproduces the issue described above.
state is a map of [immerable] classes, with patch replacing state["INTC"]
type State = Map<string, Stock>;
const errorProducingPatch = [
{
op: "replace",
path: ["INTC"],
value: makeInitialState().get("INTC"), // Stock
},
] as Patch[];
️This setup reproduces the issue described above.
state is an [immerable] class, with patch replacing state root
type State = Stock;
const errorProducingPatch = [
{
op: "replace",
path: [],
value: makeInitialState(), // Stock
},
] as Patch[];
This setup does not reproduce the issue described above.