DEV Community

Discussion on: Deep Readonly Generic in Typescript

Collapse
 
grief profile image
Grief

Your code works incorrectly for tuple types:

const works: DeepReadonly<['one'|'two', 1 | 2]> = [1, 2]; // TS2322: Type 'number' is not assignable to type 'Readonly<"one" | "two">'.
const doesntwork: DeepReadonly<{x: ['one'|'two', 1 | 2], y: string}> = {x: [1, 2], y: 'asd'}; // no error
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bwca profile image
Volodymyr Yepishev

That's a good observation, I haven't accounted for the tuples when designing it, thanks 👍

Perhaps, I'll revise it 🤓

Collapse
 
bwca profile image
Volodymyr Yepishev

Apparently it's the inferring the array type and passing it back to the Array generic that messes up the case for tuples. Turns out this step can be avoided by passing the property type directly, then the generic gets even smaller:

type DeepReadonly<T> = Readonly<{
  [K in keyof T]: 
    T[K] extends (number | string | symbol) ? Readonly<T[K]>
    : Readonly<DeepReadonly<T[K]>>;
}>
Enter fullscreen mode Exit fullscreen mode

Here's the playground with the tuple example you provided.

Collapse
 
grief profile image
Grief • Edited

I don't get, what's the benefit over this simpler variant?

type DeepReadonly<T> = {
  readonly [K in keyof T]: DeepReadonly<T[K]>;
};
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
bwca profile image
Volodymyr Yepishev

I don't see any apparent advantages, this one seems less verbose 🤔