Unexpected undefined not assigned
🐛 Bug Report
When I assign "undefined" to the prop "foo" of draft, and the prototype of base has the prop "foo" which is "undefined", the final return value is not assigned an "undefined" to the prop "foo".
To Reproduce
import { enablePatches, immerable, produceWithPatches } from "immer";
const proto = { [immerable]: true, name: undefined };
const foo = Object.create(proto);
console.log(`[hasOwnProp] foo:`, Object.prototype.hasOwnProperty.call(foo, "name"));
enablePatches();
const [foo_next, patches, _] = produceWithPatches(foo, (x) => {
console.log(`[immer] produce foo_next from immer`);
x.name = undefined;
});
console.log(`[immer] foo_next patches:`, patches);
console.log(`[hasOwnProp] foo:`, Object.prototype.hasOwnProperty.call(foo, "name"));
console.log(`[hasOwnProp] foo_next:`, Object.prototype.hasOwnProperty.call(foo_next, "name"));
foo.name = undefined;
console.log(`[vanilla] assign name manually`);
console.log(`[hasOwnProp] foo:`, Object.prototype.hasOwnProperty.call(foo, "name"));
Observed behavior
[hasOwnProp] foo: false
[immer] produce foo_next from immer
[immer] foo_next patches: []
[hasOwnProp] foo: false
[hasOwnProp] foo_next: false
[vanilla] assign name manually
[hasOwnProp] foo: true
Expected behavior
[hasOwnProp] foo: false
[immer] produce foo_next from immer
[immer] foo_next patches: [
{
op: "add",
path: [ "name" ],
value: undefined,
}
]
[hasOwnProp] foo: false
[hasOwnProp] foo_next: true
[vanilla] assign name manually
[hasOwnProp] foo: true
Adjusting the code here may solve it
src/core/proxy.ts
replace prop in state.copy_ to has(state.copy_, prop).
In this way, the corresponding prop on the prototype will not be detected
Note that in JSON undefined doesn't exist, and generally "undefined" fields are signaled by the absence of that field, so in spirit of the JSON spec I think the current behavior seems about right. Is there anything specific you need this for. Did you consider using null instead?