Преобразование типов и полиморфизм
Декоратор @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)[];
}