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];
};
Комментарии