DEV Community

Discussion on: Object.freeze() Goes Hard πŸ₯Άβ„️

Collapse
 
abustamam profile image
Rasheed Bustamam

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!

Collapse
 
mattlewandowski93 profile image
Matt

While TypeScript's readonly is great, Object.freeze() provides runtime protection that type-level immutability can't catch. This is especially important for:

  1. State Management: In Redux/Zustand, TypeScript won't stop runtime mutations that can cause bugs
  2. Library Authors: Can't guarantee all users will use TypeScript
  3. 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

Collapse
 
pseudoresonance profile image
PseudoResonance

I just wanted to correct this one mistake, #3, readonly can't "freeze" nested objects. I found this nice piece of code somewhere.

type ImmutableObject<T> = {
    readonly [K in keyof T]: Immutable<T[K]>;
};

export type Immutable<T> = {
    // eslint-disable-next-line @typescript-eslint/ban-types
    readonly [K in keyof T]: T[K] extends Function
        ? T[K]
        : ImmutableObject<T[K]>;
};

type MutableObject<T> = {
    -readonly [K in keyof T]: Mutable<T[K]>;
};

export type Mutable<T> = {
    // eslint-disable-next-line @typescript-eslint/ban-types
    -readonly [K in keyof T]: T[K] extends Function
        ? T[K]
        : MutableObject<T[K]>;
};
Enter fullscreen mode Exit fullscreen mode

Along with your previous example, the following shouldn't work.

const immutableUser: Immutable<User> = createUser('alice');
immutableUser.admin = true;
Enter fullscreen mode Exit fullscreen mode

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.

Collapse
 
ellockie profile image
Lukasz Przewlocki

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:

const a = Object.freeze({b: {c: {d: 7}}});
console.log(a.b.c.d); // 7
a.b.c.d = 88;
console.log(a.b.c.d); // 88
Enter fullscreen mode Exit fullscreen mode