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

Converting object interface that has properties with ReadonlyArray to Array

I have a certain interface that aligned with this:

interface Example {
  field_a: number | null;
  field_b: readonly string[];
  readonly field_c: string;
  nested: {
   field_d: readonly unknown[]
  }
} 

I want to apply a mutation and remove all readonly, something along like this:

type Mutable<T> = {
  -readonly [K in keyof T]: T[K] extends Readonly<T[K]> ? Mutable<T[K]> : T[K];
 };

Creating a new type Mutable<Example>, will apply Mutate to all fields, even when it’s not needed, so if I hover on field_a, the type applied is Mutable<number | null>, which is not what I want.

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

I need the final the result to be as shown below for this particular example (when doing Mutable<Example>), but should be dynamic enough to handle different interfaces.

type TransformedExample = {
  field_a: number | null;
  field_b: string[];
  field_c: string;
  nested: {
   field_d: unknown[]
  }
} 

Thanks in advance for the help!

>Solution :

It sounds like you only want to iterate the keys of object types, and not other types.

If so, then you just need one more conditional check for that in the form of T extends object:

type Mutable<T> =
  T extends object
    ? {
      -readonly [K in keyof T]:
        T[K] extends Readonly<T[K]>
          ? Mutable<T[K]>
          : T[K];
    }
    : T

WHich works like you expect:

interface Example {
  field_a: number | null;
  field_b: readonly string[];
  readonly field_c: string;
  nested: {
    field_d: readonly unknown[]
  }
}

type TransformedExample = Mutable<Example>

And TransformedType is reported as:

type TransformedExample = {
    field_a: number | null;
    field_b: string[];
    field_c: string;
    nested: {
        field_d: unknown[];
    };
}

Which is nice and clean.

See playground


In fact, you can remove the T[K] extends Readonly<T[K]> check entirely now which simplifies this a lot.

type Mutable<T> =
  T extends object
    ? { -readonly [K in keyof T]: Mutable<T[K]> }
    : T

Since you want every object property mutable, you don’t have to check if it’s read only first. You just make everything mutable, regardless of how it started.

See 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