Skip to main content

Mapped types

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

🚀Mapped Types помогают гибко манипулировать типами, уменьшая дублирование кода.

Основные возможности:

  1. Итерация по ключам
    Можно перебрать ключи одного типа (keyof) и создать новый:

    type Optional<T> = { [K in keyof T]?: T[K] };

    Это сделает все свойства T необязательными.

  2. Модификаторы (readonly, ?)
    Можно добавлять или удалять модификаторы:

     type Readonly<T> = { readonly [K in keyof T]: T[K] };
    type Mutable<T> = { -readonly [K in keyof T]: T[K] }; // Удаляет `readonly`
  3. Фильтрация ключей
    Через as в TypeScript 4.1+ можно фильтровать или преобразовывать ключи:

     type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] };

Примеры встроенных mapped types:

  • Partial<T> – все свойства необязательные.
  • Required<T> – все свойства обязательные.
  • Pick<T, K> – выбирает только указанные ключи K из T.
  • Record<K, V> – создаёт тип с ключами K и значениями V.

Пример из практики:

interface Movie {
title: string;
director: string;
awards?: string;
}

type Keys = keyof Movie; // это обычный union 'title' | 'director' | 'awards'

// Mapped type
type MovieCopy = {
[Property in keyof Movie]: number; // Property переменная, в результате просто изменится тип на number у всех ключей
};

// делаем все поля только для чтения
type ReadonlyMovie = {
readonly [Property in keyof Movie]: Movie[Property];
};

// делаем все поля опциональными
type OptionalMovie = {
readonly [Property in keyof Movie]?: Movie[Property];
};

// делаем все поля обязательными
type RequiredMovie = {
readonly [Property in keyof Movie]-?: Movie[Property];
};

// убираем readonly из всех полей
type EditableMovie = {
-readonly [Property in keyof Movie]-?: Movie[Property];
};

type MovieSetters = {
[Property in keyof Movie as `set${Capitalize<Property>}`]-?: (
value: Movie[Property]
) => void;
};

type MovieGetters = {
[Property in keyof Movie as `set${Capitalize<Property>}`]-?: () => Movie[Property];
};