Тестовое задание на Angular. Создание базовых интерфейсов.

Aleksandr Serenko
F.A.F.N.U.R
Published in
3 min readJul 5, 2021

В данной статье рассмотрим создание интерфейсов для сущностей, которые будут использованы в приложении. Рассмотрим концепт DTO-Entity-Model на примере реализации Room, Building и Person.

Для того, чтобы забронировать номер (room), нужно на карте выбрать подходящий вариант и кликнуть забронировать. Каждая комната принадлежит какому-то зданию (building), где здание имеет какого-то собственника (person).

Интерфейс person в person/common/person.interface.ts:

Концепт DTO-Entity-Model

Каждая сущность (что-то полученное извне, например, данные с сервера) может быть разложена на 3 базовых типа:

  • DTO (Data Transfer Object) — объект получаемый с backend’а или внешнего сервиса. DTO никогда не переопределяется и всегда соответствует response’у сервера
  • Entity — обеъкт, который получается из DTO, который в дальнейшем будет сохранен в хранилище Redux’а. Entity обладает рядом новых свойств, которые необходимы для работы приложения.
  • Model — объект, который наследуется от Entity и добавляет ряд свойств, которые не должны быть сохранены в хранилище. Примером сущности может быть реализация дат. Например с сервера, возвращается поле created — которое содержит дату создания сущности, в виде строки. Для того, чтобы всегда иметь свойство типа Date, можно у модели создать новое поле — createdDate: Date и его заполнять в момент получения из хранилища Redux.

Важно отметить, что все трансформации происходят на уровне State’а. В частности, вызывается события загрузки сущностей. Сущности возвращаются в виде DTO и на их основе создаются Entity. После того, как сущности созданы и сохранены в state’е, они могут быть запрошены. И при запросе уже загруженной сущности из хранилища, она приводится к Модели, в которой добавляются те или иные характеристики.

Из примера выше, мы имеем PersonDdo:

export interface PersonDto {
readonly id: number;
readonly firstName: string;
readonly lastName: string;
readonly middleName: string | null;

readonly phone: string;
readonly buildings: number[];
readonly avatar?: string;

readonly created: string;
readonly updated: string;
}

На его основе создается PersonEntity:

export interface PersonEntity {
id: number;
firstName: string;
lastName: string;
middleName: string | null;
phone: string;
buildings: number[];
avatar?: string;
created: string;
updated: string;

personRemoveRun: boolean;
personRemoveError: Record<string, any> | null;
personChangeRun: boolean;
personChangeError: Record<string, any> | null;
personBuildingRemoveRun: boolean;
personBuildingRemoveError: Record<string, any> | null;
personBuildingAddRun: boolean;
personBuildingAddError: Record<string, any> | null;
}

Как видно из примера, в entity есть ряд полей, которые будут использоваться в state, в частности поля:

personRemoveRun: boolean;
personRemoveError: Record<string, any> | null;
personChangeRun: boolean;
personChangeError: Record<string, any> | null;
personBuildingRemoveRun: boolean;
personBuildingRemoveError: Record<string, any> | null;
personBuildingAddRun: boolean;
personBuildingAddError: Record<string, any> | null;

И уже на основании PersonEntity создается модель Person:

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Person extends PersonEntity {}

Которая в данном случае просто совпадает с PersonEntiy.

Остальные интерфейсы и константы из person.interface.ts будут рассмотрены в следующих статьях.

Аналогично добавим интерфейсы для Building в building/common/building.interface.ts:

Интерфейс Room в room/commin/room.interface.ts:

Отметим, что в реализации мы не ссылаемся на сущности в описании интерфейсов, а только на их ID. Это необходимо для того, чтобы не было цикличных редиректов, а также поможет использовать реляционность, для более простой работы (по аналогии с базами данных). Все данные будут представлены набором справочников (persons, builidings, rooms), где person может иметь несколько зданий, а каждое здание имеет одну или более комнат.

Ссылки

Вернуться к оглавлению — Введение.

Следующая статья — Установка redux и создание root store.

Предыдущая статья — Создание модулей и компонентов.

Все исходники на github/fafnur/barinb.

Группа в Medium: https://medium.com/fafnur
Группа в Vkontakte: https://vk.com/fafnur
Группа в Facebook: https://www.facebook.com/groups/fafnur/
Telegram канал: https://t.me/f_a_f_n_u_r
Twitter: https://twitter.com/Fafnur1
LinkedIn: https://www.linkedin.com/in/fafnur

--

--

Aleksandr Serenko
F.A.F.N.U.R

Senior Front-end Developer, Angular evangelist, Nx apologist, NodeJS warlock