Mapped Types — это типы, которые строятся динамически путём преобразования (переименования, модификации) всех свойств другого типа. Синтаксис основан на конструкции in:
type Readonly<T> = { readonly [K in keyof T]: T[K]; } type User = { name: string; age: number; } const u: Readonly<User> = { name: 'Eve', age: 22 }; u.name = 'Bob'; // Ошибка: name — только для чтения
Нюансы:
-? или +?.Пример со всеми модификаторами:
type PartialMutable<T> = { -readonly [K in keyof T]?: T[K]; };
«Применив mapped type с модификатором optional, влияет ли это только на свойства первого уровня или на вложенные объекты тоже?»
Ответ: Нет, mapped type с optional ? влияет ТОЛЬКО на свойства первого уровня. Вложенные объекты нужно преобразовывать отдельно, часто с помощью рекурсии или дополнительных mapped types.
Пример:
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
История
В одном проекте на экономии времени применяли стандартный Partial<T> для deep-объема формы. Однако, поля второго и третьего уровня не стали опциональными, что привело к неожиданным ошибкам на runtime при отсутствии вложенных ключей.
История
Была попытка убрать readonly свойства только в дочерних объектах, применив mapped type только на верхний уровень:
type Mutable<T> = { -readonly [K in keyof T]: T[K] }
В результате, поля типа { readonly foo: { readonly bar: number } } оставались неизменными во вложенности, что запутало команду и усложнило поддержку.
История
В сложной модели данных применили вложенные mapped types для пересечения нескольких utility types (например, Readonly & Partial). Из-за неправильного порядка их композиции возникли неожиданные конфликты по совместимости типов, и компилятор начал выводить запутанные сообщения об ошибках.