I created a Mutable type utility which intended to convert immutable structures to mutable ones. This includes readonly xxx[]
types as well as the Readonly<T>
operators. In my local environment it wasn't working and so I copied it to a TS Playground and to my shock and horror it worked perfectly. Then I noticed that my type util was dependent on a type utility that didn't exist. I'd have thought I'd end up with an any type or something equally as ugly but no ... it worked.
Here's that state of the playground: Working when Broken
The code for Mutate is:
export type Mutable<T> = {
-readonly [K in keyof T]: IsObject<T[K]> extends true
? Mutable<T[K]>
: T[K] extends Readonly<any>
? T[K] extends Readonly<infer R>
? R
: never
: T[K];
};
This code relies on a the IsObject
utility which I created but forgot to bring into the playground above. This utility looks like this:
type IsObject<T> = Mutable<T> extends Record<string, any>
? T extends <A extends any[]>(...args: A) => any
? false // when a function with props is found, categorize as a function not object
: true
: false;
The new playground with previously missing IsObject now included: Playground
Sadly, the first two tests are no longer passing:
The types passed into these two first tests were similar:
These passed to Mutate<T>
produce the same results and some useful conversion has been made but while baz
was converted to from a readonly array to a mutable array, the property bar
remains with the Readonly<"yes" | "no">
Can anyone help me understand how to remove these Readonly<T>
props? Can anyone explain how it all works when I use a non-existing type utility?
Adding to comments ...