Great writeup! I think TypeScript makes Object.freeze a bit redundant though. You can annotate props as readonly which will cause a type error, and the as const will also work with keyof.
But without TS, Object.freeze can definitely save your butt!
While TypeScript's readonly is great, Object.freeze() provides runtime protection that type-level immutability can't catch. This is especially important for:
State Management: In Redux/Zustand, TypeScript won't stop runtime mutations that can cause bugs
Library Authors: Can't guarantee all users will use TypeScript
Deep Freezing: Protects nested objects that readonly can't catch
I see them as complementary tools - TypeScript for compile-time safety and Object.freeze() for runtime guarantees
I used it myself to protect against any accidents. I needed to keep the state immutable, so I had a method to deep copy, cast to the mutable object, make the changes, then cast it back to being immutable.
Great writeup! I think TypeScript makes Object.freeze a bit redundant though. You can annotate props as readonly which will cause a type error, and the
as constwill also work with keyof.But without TS, Object.freeze can definitely save your butt!
While TypeScript's
readonlyis great, Object.freeze() provides runtime protection that type-level immutability can't catch. This is especially important for:I see them as complementary tools - TypeScript for compile-time safety and Object.freeze() for runtime guarantees
I just wanted to correct this one mistake, #3, readonly can't "freeze" nested objects. I found this nice piece of code somewhere.
Along with your previous example, the following shouldn't work.
I used it myself to protect against any accidents. I needed to keep the state immutable, so I had a method to deep copy, cast to the mutable object, make the changes, then cast it back to being immutable.
Re #3, as you mentioned in the article, it doesn't deep-freeze, only shallow freezes, unless I don't understand something here.
For example: