Перейти к основному содержимому

Преобразование типов и полиморфизм

Декоратор @Type — это мощный инструмент для преобразования простых JSON-объектов в реальные экземпляры классов.

Это необходимо для поддержания типобезопасности, использования методов класса и обработки сложных структур данных, таких как вложенные объекты и полиморфные массивы.

Базовое вложенное сопоставление

Когда свойство должно быть экземпляром другого класса, используйте @Type, чтобы указать целевой класс.

import { Body, Type } from 'express-cargo';

class Profile {
@Body()
bio!: string;
}

class User {
@Body()
name!: string;

@Body()
@Type(() => Profile) // Автоматически преобразует в экземпляр Profile
profile!: Profile;
}

Разрешение циклических зависимостей

Если два класса ссылаются друг на друга (например, у User много Posts, а Post принадлежит Author), использование прямой ссылки вызовет ReferenceError, потому что класс может быть еще не определен.

Чтобы решить эту проблему, используйте Thunk (стрелочную функцию) для отложенного разрешения класса.

class Post {
@Body()
title!: string;

@Body()
@Type(() => User) // Разрешается лениво, чтобы избежать ошибки "User is not defined"
author!: User;
}

class User {
@Body()
name!: string;

/**
* @Type автоматически определяет тип массива через метаданные.
* Явный декоратор @List(Post) не требуется.
*/
@Body()
@Type(() => Post)
posts!: Post[];
}

Динамическое разрешение типов

Самая продвинутая функция @Type — это определение целевого класса во время выполнения на основе входящих данных. Это особенно полезно для обработки наследования и полиморфизма.

Функциональный распознаватель (Resolver)

Вы можете передать функцию, которая проверяет данные и возвращает соответствующий класс.

class Example {
@Type((data) => {
if (data.type === 'video') return Video;
if (data.type === 'image') return Image;
return DefaultMedia;
})
featuredMedia!: Video | Image | DefaultMedia;
}

Структурный дискриминатор

Для более чистого и декларативного подхода используйте опцию discriminator, чтобы сопоставить определенные значения свойств с их соответствующими классами.

class Example {
@Type(() => Media, {
discriminator: {
property: 'kind',
subTypes: [
{ name: 'v', value: Video },
{ name: 'i', value: Image },
],
},
})
gallery!: (Video | Image)[];
}