Deep Readonly
Проблема
Реализовать тип DeepReadonly<T> который делает свойства объекта неизменяемыми
(рекурсивно!). Например:
type X = {
  x: {
    a: 1;
    b: "hi";
  };
  y: "hey";
};
type Expected = {
  readonly x: {
    readonly a: 1;
    readonly b: "hi";
  };
  readonly y: "hey";
};
const todo: DeepReadonly<X>; // should be same as `Expected`
Решение
Эта проблема схожая с тем, что мы делали в Readonly<T>.
Разница в том, что здесь нужно делать это рекурсивно.
Начнём с классической реализации и сделаем Readonly<T>:
type DeepReadonly<T> = { readonly [P in keyof T]: T[P] };
Но, как вы уже догадались, этот тип не сделает все свойства неизменяемыми, а
только те, что находятся на первом уровне вложенности. Причина заключается в
том, что если T[P] это не примитив, а объект, то его свойства останутся
нетронутыми, а значит не будут неизменяемыми.
Поэтому, заменим T[P] на рекурсивный вызов DeepReadonly<T>. И раз мы уже
начали использовать рекурсивный вызов, не забываем о базовом случае. Алгоритм
простой. В случае, если T[P] это объект, идём вглубь и вызываем
DeepReadonly, иначе - возвращаем T[P] без изменений.
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends Record<string, unknown>
    ? DeepReadonly<T[P]>
    : T[P];
};
Комментарии