TypeScript - Mutability and inversion of Readonly<T>
Asked Answered
I

2

10

Assume that I have the following mutable class:

class Foo {
    constructor(public bar: any) { }
}

I can define readonly instances of this class like so:

const foo: Readonly<Foo> = new Foo(123);
foo.bar = 456; // error, can't reassign to bar because it's readonly.

What I'd like to be able to do is the inverse of this, where the class is immutable:

class Foo {
    constructor(public readonly bar: any) { }
}

And then be able to make mutable versions like so:

const foo: Mutable<Foo> = new Foo(123);
foo.bar = 456;

Is this possible?

Insusceptible answered 27/5, 2020 at 7:59 Comment(3)
You can cast Foo to Mutable<Foo>, but it is not recommended since it is the contract of your Foo class... Why would you want to do it?Mercorr
@htn because I believe that mutability should be opt-in, rather than opt-out. How would I cast to Mutable<Foo> (where presumably Mutable<T> is a type like Readonly<T>)?Insusceptible
You can define Mutable such as: type Mutable<T> = { -readonly [P in keyof T]: T[P] };. However, it's dangerous because you can change the implementation of your class Foo later thinking that bar is readonly ==> It can break your app.Mercorr
S
8

Yes, you can use -readonly in type definition.

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

const foo: Mutable<Foo> = new Foo(123);
foo.bar = 456;

Playground

But remember it's only type definition, it doesn't change original logic.

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

class Foo {
    get test(): boolean {
      return true;
    }

    constructor(public readonly bar: any) { }
}

const foo: Mutable<Foo> = new Foo(123);
foo.bar = 456;
foo.test = false; // oops, it will cause an error.
Sears answered 27/5, 2020 at 8:11 Comment(0)
L
0

Slight modification to the accepted answer that can get you past the nested readonly definitions:

type Mutable<T> = {
  -readonly [P in keyof T]: Mutable<T[P]>;
};
Ljoka answered 19/6 at 22:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.