Can TypeScript's `readonly` fully replace Immutable.js?

While it is true that the readonly modifier of TypeScript only exists at design type and does not affect runtime code, this is true of the entire type system. That is, nothing stops you at runtime from assigning a number to a variable of type string. So that answer is kind of a red herring... if you get warned at design time that you're trying to mutate something marked as const or readonly, then that would possibly eliminate the need for extensive runtime checking.

But there is a major reason why readonly is insufficient. There is an outstanding issue with readonly, which is that currently (as of TS3.4), types that differ only in their readonly attributes are mutually assignable. Which lets you easily bust through the protective readonly shell of any property and mess with the innards:

type Person = { name: string, age: number }
type ReadonlyPerson = Readonly<Person>;

const readonlyPerson: ReadonlyPerson = { name: "Peter Pan", age: 12 };
readonlyPerson.age = 40; // error, "I won't grow up!"

const writablePerson: Person = readonlyPerson; // no error?!?!
writablePerson.age = 40; // no error!  Get a job, Peter.

console.log(readonlyPerson.age); // 40

This is pretty bad for readonly. Until that gets resolved, you might find yourself agreeing with a previous issue filer who had originally named the issue "readonly modifiers are a joke" .

Even if this does get resolved, readonly might not cover all use cases. You'd also need to walk through all interfaces and types in your libraries (or even the standard libraries) and remove methods that mutate state. So all uses of Array would need to be changed to ReadonlyArray and all uses of Map would need to be changed to ReadonlyMap, etc. Once you did this you'd have a fairly typesafe way to represent immutability. But it's a lot of work.

Anyway, hope that helps; good luck!


The purpose of Immutable.js is not to prevent a developer from doing an illegal mutation at compile time. It provides a convenient API to create copies of an object with some of its properties changed. The fact that you get type safeness on objects that you manage with immutable.js is basically just a side effect of using it.

Typescript is "just" a typing system. It does not implement any of the features Immutable.js does to make copies of immutable objects. All it does, when declaring a variable as readonly, is to check at compile time that you do not mutate it. How you design your code to handle immutability is not the scope of a typing system and you would still need a way of dealing with it.

React ensures immutability by providing a method setState instead of mutating the state object directly. It takes care of merging the changed properties for you. But if you e.g. use redux you may want a convenient solution to handle immutability too. That is what Immutable.js provides and typescript never will and it is independent of whether you like the api or not.