Right now if you clone frozen object with spread operator the resulting object will not be frozen.
const a = Object.freeze({x:1});
const b = {...a, y: 1}; // not frozen!
const b1 = Object.freeze({...a, y: 1}); // too verbose!
I propose adding {propagate: boolean} configuration property/parameter to Object.freeze that will make the frozen state automatically propagated with spread operators.
const a = Object.freeze({x: 1}, {propagate: true});
const b = {...a, y: 2}; // frozen!
In comparison, Object.freeze can be used with existing syntax. Most well written applications have a lot/most objects that are effectively immutable but it is not enforced anywhere because it is too cumbersome at the moment (unless you reach out for 3rd party libs and even then they won't help with standard spread operator).
With this proposal you can simply freeze objects in single place (e.g. after deserializing) and have it enforced throughout your entire program. With little to no code changes.
For maximum effectiveness should be combined with deep freezing (ideally available as another configuration property of Object.freeze).
This could also cause unexpected breaking changes to libraries. For example:
function omit(obj_, keys) {
const obj = { ...obj_ }
for (const key of keys) {
delete obj[key]
}
return obj
}
Such a function will properly work with both frozen and non-frozen objects. But, it will cause some really weird and unexpected behaviors for objects that propagate their frozeness.
I think what's really needed here is just a shorthand for freezing objects, so that the Object.freeze({ ...x, y: 2 }) case isn't so verbose. This is exactly what this proposal seeks to provide.