Object.freeze / Object.seal in typescript

If you want runtime and compile time checks you could do,

export const frozen:Readonly<{a:number}> = Object.freeze({a:1});

however the following, already gives me a TypeError: Cannot assign to read only property

export const frozen = Object.freeze({a:1});

Simplest Solution: as const

This represents a deep freeze of immutability through all levels of objects or arrays.

const a = {
    b: 1,
    c: {d: 'e'},
    f: ['g', 'h'],
} as const

None of these will allow overwriting

a = 'not'
a.b = 'going'
a.c.d = 'to'
a.f[1] = 'change'

All result in error "TS2540: Cannot assign to '<name>' because it is a read-only property."

NOTE: Custom objects may not be fully immutable, depending on your implementation.

Bonus: If using as an enum replacement, you can add this line

type a = typeof a[keyof typeof a]

Immutable Parameter with Immutable<>

This does the same thing as as const to deep freeze a parameter

// Add this and make it reuseable
type Immutable<T> = {
    readonly [K in keyof T]: Immutable<T[K]>
}

Define type within <>, i.e. Immutable<MyType>

_method = (a: Immutable<{b:{c:{d:[string]}}}>) => {
    // This will complain
    a.b.c.d[0] = ""
}

Official Docs


is there other way of making sure object remains immutable?

It depends on the level of insurance that you want to have.

If you want to make sure that no consumer, be it TypeScript or JavaScript code, could modify object properties at runtime, Object.freeze is the way to do it.

If compile-time checks are sufficient, for example when all consumer code is guaranteed to be TypeScript-only and typechecked, you can use ReadOnly generic type, which takes an object type and makes all properties readonly. In fact, Object.freeze() is declared in library type definitions as returning ReadOnly-modified type of its argument:

freeze<T>(o: T): Readonly<T>;

For seal, there is no way to represent sealed object in the type system, Object.seal() is declared to return the same type it receives:

seal<T>(o: T): T;

and Object.seal() is the only way to go.