Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object.freeze / Object.seal in typescript

Is Object.freeze suggested in Typescript or is there other way of making sure object remains immutable?

Since const only guards instance, but not properties, this is obviously not an answer I'm looking for.

like image 544
Miroslav Jonas Avatar asked Feb 05 '18 19:02

Miroslav Jonas


2 Answers

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.

like image 177
artem Avatar answered Sep 22 '22 13:09

artem


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

like image 36
Gibolt Avatar answered Sep 21 '22 13:09

Gibolt