Yuzhe's Blog

yuzhes

DeepMutable

DeepMutable

Problem Link

Problem

Implement a generic DeepMutable<T> which make every parameter of an object — and its sub-objects recursively — mutable.

type X = {
  readonly title: string
  readonly settings: {
    readonly speed: number
    readonly resolution: { readonly width: number }
  }
}

type Expected = {
  title: string
  settings: {
    speed: number
    resolution: { width: number }
  }
}

type Todo = DeepMutable<X> // Expected

Solution

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

How it works:

  1. -readonly removes the readonly modifier from every key.
  2. If the value type is itself an object, recurse with DeepMutable.
  3. Primitive values are kept as-is.

Note: Functions satisfy extends object but we typically don’t want to recurse into them. For safety you can add a function guard:

type DeepMutable<T extends object> = {
  -readonly [K in keyof T]: T[K] extends (...args: any[]) => any
    ? T[K]
    : T[K] extends object
      ? DeepMutable<T[K]>
      : T[K]
}

Key Takeaways