Главная Категории Контакты Поиск

Модификаторы перебора типов TypeScript

Создание явных и читаемых типов объявлений с помощью модификатора перебора типов TypeScript.

TypeScript·05.11.2019·читать 2 мин 🤓·Автор: Alexey Myzgin

Используя необязательный знак + вместе с модификаторами типа, мы можем создавать более явные и читабельные объявления типов. Также можем использовать знак - (минус) для удаления необязательных объявлений из свойств ?.

Например: у нас есть interface; можем использовать модификаторы перебора типов, чтобы сделать все его свойства доступными только для чтения readonly.

interface ICar {
  name: string;
  age: number;
}

type ReadonlyCar = {
  readonly [K in keyof ICar]: ICar[K];
};

Подобный тип может быть полезен, например, для state приложения Redux, потому что state должно быть неизменным.

Мы не должны быть в состоянии изменить любое из его свойств, как только объект был создан. Модификаторы перебора типов стали отличным дополнением к языку, поскольку они позволяют легко расширять существующие типы и применять массовые изменения ко всем их свойствам.

Теперь, если мы объявим две модели машины car: первый объект изменчив, другой - только для чтения; затем попробуем изменить их данные, то заметим, что во втором случае у нас будет ошибка.

const car: ICar = {
  name: "Mercedes",
  age: 2
};

const readOnlyCar: ReadonlyCar = {
  name: "BMW",
  age: 5
};

car.age = 8;
readOnlyCar.age = 10; // Cannot assign to 'age' because it is a read-only property

В случае с readOnlyCar.age, TypeScript говорит нам, что age только для чтения - Cannot assign to 'age' because it is a read-only property.

И это нормально, ведь мы указали, что все его свойства только для чтения. Статус readonly (только для чтения) - это не единственное, что мы можем изменить в модификаторах перебора типов.

Мы можем указать, что все свойства не обязательны через ?.

type ReadonlyCar = {
  readonly [K in keyof ICar]?: ICar[K];
};

Также, можем указать что все свойства - строки, или сделать каждое свойство как объединение их исходного типа и строки через вертикальную черту |. Вариантов много.

type ReadonlyCar = {
  readonly [K in keyof ICar]?: ICar[K] | string;
};

Однако, с синтаксисом readonly [K in keyof ICar]: ICar[K]; мы можем только добавлять новые элементы в существующие типы. Можем добавить флаг readonly, или ?.

Если у оригинального типа есть свойство которое необязательно, например:

interface ICar {
  name: string;
  age: number;
  color?: string;
}

Мы можем убрать флаг необязательно - ?. Начиная с TypeScript 2.8, стало возможным добавлять знак минус - перед символом, который хотим удалить.

type ReadonlyCar = {
  readonly [K in keyof ICar]-?: ICar[K];
};

Как только мы добавили знак минус, TypeScript тут же начал выдавать ошибку в const readOnlyCar. Это потому что мы внезапно пропустили обязательное свойство в этом новом объекте. Как только добавим новое поле color, ошибка исчезнет.

const readOnlyCar: ReadonlyCar = {
  name: "BMW",
  age: 5,
  color: "black"
};

Поскольку у нас есть гибкость со знаком -, чтобы удалять флаги из наших типов, знак + также был добавлен к этой функции. Мы можем более четко сказать, что именно добавляем и что удаляем.

type ReadonlyCar = {
  +readonly [K in keyof ICar]-?: ICar[K];
};

Теперь другим разработчикам, читающим этот тип, стало понятнее, что мы берем оригинальный интерфейс ICar, удаляем все необязательные модификаторы -? и добавляем флаг +readonly для всех свойств.

Модификаторы перебора типа полезны, если:

  • есть интерфейс, который невозможно изменить напрямую (например, из библиотеки);
  • есть интерфейс, который хотим продолжать использовать для некоторых целей, и создать его небольшую вариацию (с использованием модификаторов) для использования в других целях.

В обоих случаях модификаторы перебора типа “следуют” форме исходного интерфейса; даже если в будущем исходный интерфейс изменится/будет изменен они просто расширят его в соответствии с указанными правилами.

Website, name & logo
Copyright © 2022. Alex Myzgin