Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Convert TypeScript Map to Readonly Map generically

In order to better communicate immutability of an object during development, I want to convert an entire object to read only. Basically, the class has a copy() function, which should return a read-only copy of itself. The important part is only, that the type is read only, so compiler errors are thrown, during development. The actual runtime behavior is not as important.

Using the Readonly<> utility type, only primitive types are cast to read only. But this class also has a Map, which even is generic. How can I convert the Map to a ReadonlyMap without losing the generic values?

Here is a small code snippet to illustrate the problem:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class MyClass<T> {
    public name: string = "Name";
    public data: Map<string, T> = new Map<string, T>();

    // "this" is used for correct typing of inheriting classes here
    public copy(): ReadonlyClass<this> {
        return structuredClone(this) as ReadonlyClass<this>;
    }
}

export type ReadonlyClass<T extends MyClass<any>> = {
  [P in keyof T]: T[P] extends Map<string, any>
    ? ReadonlyMap<string, /* what can I put here? */>
    : Readonly<T[P]>;
};

I’ve tried getting the type via the values() function of the map: ReturnType<T[P]['values']>, but that returns an IterableIterator, and as far as I can see, there is no way to extract the value type from there.

Is this just not possible with TypeScripts current feature set?

Thanks!

>Solution :

The infer keyword comes in handy here. We can use it to infer both the key-type K and the value-type V of the Map and use them to construct the ReadonlyMap<K, V>.

export type ReadonlyClass<T extends MyClass<any>> = {
  [P in keyof T]: T[P] extends Map<infer K, infer V>
    ? ReadonlyMap<K, V>
    : Readonly<T[P]>;
}

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading