Readonly 2
Проблема
Реализовать тип MyReadonly2<T, K>
. Тип параметр K
содержит список свойств
T
, которые должны быть указаны как readonly
. В случае, если K
не передали
в аргументах, все свойства T
должны быть readonly
. Например:
interface Todo {
title: string;
description: string;
completed: boolean;
}
const todo: MyReadonly2<Todo, "title" | "description"> = {
title: "Hey",
description: "foobar",
completed: false,
};
todo.title = "Hello"; // Error: cannot reassign a readonly property
todo.description = "barFoo"; // Error: cannot reassign a readonly property
todo.completed = true; // OK
Решение
Эту проблему можно считать продолжением Readonly<T>
. Всё
то же, кроме того, что теперь у нас появляется новый тип параметр K
, через
который указываем, какие свойства сделать неизменяемыми.
Начнём со случая, когда K
это пустое объединение, то есть, ничего не должно
быть неизменяемым. Всё просто - возвращаем T
без изменений.
type MyReadonly2<T, K> = T;
Теперь, обработаем случай, когда у нас указаны свойства в K
. Используем типы
пересечений и добавим к нашему T
новый объект. В этом объекте, используя
сопоставляющие типы, перечислим свойства из K
и добавим к ним модификатор
readonly
.
type MyReadonly2<T, K> = T & { readonly [P in K]: T[P] };
Выглядит как решение, но получаем ошибку “Type ‘P’ cannot be used to index type
‘T’”. И это правда, у нас нет ограничений на K
. Ограничим его до “ключи из
T
”.
type MyReadonly2<T, K extends keyof T> = T & { readonly [P in K]: T[P] };
А теперь работает? Нет! Мы забыли о случае, когда K
не передан вовсе, как
аргумент. Это тот случай, когда MyReadonly2
ведёт себя как встроенный
Readonly<T>
. Добавим к K
тип параметр по умолчанию “все ключи из T
”.
type MyReadonly2<T, K extends keyof T = keyof T> = T & {
readonly [P in K]: T[P];
};
Комментарии