Как работает Mapped Types в TypeScript?

Mapped Types в TypeScript представляют собой мощный инструмент для создания новых типов данных на основе существующих. Они позволяют нам автоматически применять операции или модификации ко всем свойствам или подмножеству свойств существующего типа.

Примерно так выглядит синтаксис Mapped Types:

type NewType = { [P in keyof OldType]: NewValueType }

В этом примере OldType - это исходный тип, P - переменная для итерации по всем свойствам OldType, keyof - ключевое слово TypeScript, которое позволяет получить все ключи объекта или типа в виде объединения строковых литералов. NewValueType - это новый тип значения, который мы хотим присвоить для каждого свойства.

Давайте рассмотрим несколько примеров для лучшего понимания.

Пример 1: Добавление модификатора "readonly" ко всем свойствам объекта

type Person = {
  name: string;
  age: number;
};

type ReadonlyPerson = { readonly [P in keyof Person]: Person[P] };

const person: ReadonlyPerson = { name: "John", age: 25 };
person.name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property.

В этом примере мы создаем новый тип ReadonlyPerson, используя Mapped Type. Мы присваиваем каждому свойству из типа Person его оригинальное значение, но указываем модификатор "readonly" перед каждым свойством. Когда мы создаем объект типа ReadonlyPerson, все его свойства становятся только для чтения, и мы не можем изменять их значения.

Пример 2: Преобразование всех свойств объекта в опциональные

type PartialPerson = { [P in keyof Person]?: Person[P] };

const partialPerson: PartialPerson = {};
partialPerson.name = "John";

В этом примере мы используем Mapped Type для создания нового типа PartialPerson, который делает все свойства типа Person опциональными. Теперь мы можем создавать объекты типа PartialPerson, устанавливая значения только для нужных нам свойств.

Пример 3: Преобразование типа всех свойств объекта

type AgeAsStringPerson = { [P in keyof Person]: string };

const ageAsStringPerson: AgeAsStringPerson = { name: "John", age: "25" };

В этом примере мы создаем новый тип AgeAsStringPerson, где каждое свойство типа Person имеет тип string. Это пример использования Mapped Type для преобразования типа значения всех свойств объекта.

Mapped Types в TypeScript предоставляют удобный способ работы с типами данных, позволяя нам создавать новые типы на основе существующих типов. Они могут быть эффективно использованы для валидации данных, описания API-интерфейсов и преобразования типов данных в процессе разработки приложений на TypeScript.