Декоратор @Transform используется для определения правил
преобразования значений при сериализации и десериализации объектов. Он
относится к библиотеке class-transformer, но в связке с
class-validator часто применяется в DTO-слоях для
подготовки данных перед валидацией и дальнейшей обработкой.
Основная задача заключается в том, чтобы модифицировать входящие или исходящие значения свойств класса: нормализовать строки, приводить типы, вычислять производные значения, фильтровать или адаптировать данные под внутренние требования приложения.
Ключевая особенность — выполнение преобразования на уровне свойства без необходимости писать отдельную логику в сервисах или контроллерах.
Декоратор принимает функцию преобразования и опциональный объект конфигурации:
import { Transform } from 'class-transformer';
class UserDto {
@Transform(({ value }) => value.trim())
name: string;
}
Функция получает объект контекста, содержащий:
value — исходное значение свойстваobj — исходный объект целикомkey — имя свойстваtype — направление трансформации
(plainToClass или classToPlain)Используется при преобразовании обычного объекта в экземпляр класса. На этом этапе входящие данные нормализуются.
class ProductDto {
@Transform(({ value }) => Number(value))
price: number;
}
Вход:
{
"price": "100"
}
Результат:
ProductDto { price: 100 }
Применяется при сериализации экземпляра класса в обычный объект. Используется для формирования ответа API.
class UserDto {
@Transform(({ value }) => value.toUpperCase(), { toPlainOnly: true })
role: string;
}
Конфигурация позволяет ограничить направление применения трансформации:
toClassOnly — только при создании классаtoPlainOnly — только при сериализацииclass ExampleDto {
@Transform(({ value }) => parseInt(value), { toClassOnly: true })
id: number;
}
Валидация и трансформация часто используются совместно, где
@Transform подготавливает данные, а
class-validator проверяет результат.
import { IsNumber } from 'class-validator';
import { Transform } from 'class-transformer';
class OrderDto {
@Transform(({ value }) => Number(value))
@IsNumber()
quantity: number;
}
Сначала выполняется преобразование строки в число, затем проверка типа.
Наиболее распространённый сценарий — нормализация строковых данных.
class ProfileDto {
@Transform(({ value }) => typeof value === 'string' ? value.trim() : value)
displayName: string;
}
class ProfileDto {
@Transform(({ value }) =>
typeof value === 'string' ? value.toLowerCase() : value
)
email: string;
}
Входящие данные из HTTP-запросов часто приходят в виде строк.
class StatsDto {
@Transform(({ value }) => Number(value))
views: number;
}
class StatsDto {
@Transform(({ value }) => {
const parsed = Number(value);
return Number.isNaN(parsed) ? 0 : parsed;
})
likes: number;
}
HTTP-запросы часто содержат булевы значения в строковом виде.
class FeatureDto {
@Transform(({ value }) => value === 'true' || value === true)
isActive: boolean;
}
Расширенный вариант с поддержкой различных форматов:
class FeatureDto {
@Transform(({ value }) => {
if (typeof value === 'boolean') return value;
return value === '1' || value === 'true' || value === 'yes';
})
enabled: boolean;
}
class TagsDto {
@Transform(({ value }) =>
typeof value === 'string' ? value.split(',') : value
)
tags: string[];
}
Вход:
{
"tags": "nodejs,typescript,backend"
}
Результат:
["nodejs", "typescript", "backend"]
class TagsDto {
@Transform(({ value }) =>
Array.isArray(value)
? value.map(v => v.trim()).filter(Boolean)
: value
)
tags: string[];
}
@Transform может применяться для преобразования сложных
структур.
class AddressDto {
@Transform(({ value }) => value?.toUpperCase())
city: string;
}
class UserDto {
@Transform(({ value }) => value && new AddressDto(value))
address: AddressDto;
}
Контекст трансформации позволяет учитывать метаданные свойства.
class AuditDto {
@Transform(({ value, key }) => {
if (key === 'createdAt') {
return new Date(value);
}
return value;
})
createdAt: Date;
}
Трансформация может зависеть от состояния объекта:
class AccountDto {
@Transform(({ value, obj }) => {
if (obj.type === 'admin') {
return value;
}
return null;
})
secretKey: string;
}
Несколько декораторов применяются последовательно:
class SampleDto {
@Transform(({ value }) => value.trim())
@Transform(({ value }) => value.toLowerCase())
username: string;
}
Порядок выполнения влияет на итоговый результат.
При обработке внешних данных важна устойчивость к ошибкам.
class SafeDto {
@Transform(({ value }) => {
if (typeof value !== 'string') return '';
return value.trim();
})
title: string;
}
class ItemDto {
@Transform(({ value }) => ({
id: Number(value.id),
name: String(value.name)
}))
item: { id: number; name: string };
}
@Transform(({ value }) => value.trim())
Если значение не строка, возникнет ошибка выполнения.
Изменение внешних объектов внутри transform-функции приводит к непредсказуемому поведению:
@Transform(({ obj }) => {
obj.modified = true;
return obj.value;
})
Трансформации выполняются при каждом создании экземпляра класса или
сериализации. При больших массивах данных избыточная логика внутри
@Transform может стать узким местом.
Рекомендуется:
Типичный поток обработки данных:
@Transformclass-validatorclass CreateUserDto {
@Transform(({ value }) => value.trim())
@IsString()
name: string;
@Transform(({ value }) => Number(value))
@IsNumber()
age: number;
}
В экосистеме NestJS трансформации активируются через
ValidationPipe с параметром
transform: true.
app.useGlobalPipes(
new ValidationPipe({
transform: true
})
);
Без включённой трансформации @Transform не
применяется.
Порядок обработки данных:
@Transformclass-transformer внутренние преобразованияclass-validator проверкиЛюбое изменение на уровне @Transform влияет на
последующую валидацию.
class ResponseDto {
@Transform(({ value }) => ({
id: value._id,
createdAt: value.created_at
}))
data: any;
}
class SecretDto {
@Transform(({ value }) => value.replace(/.(?=.{4})/g, '*'))
cardNumber: string;
}
class UserDto {
@Transform(({ obj }) => `${obj.firstName} ${obj.lastName}`)
fullName: string;
}
Механизм строго синхронный и ориентирован на локальные преобразования данных.
@Transform формирует промежуточный слой между внешними
данными и внутренними структурами. Он уменьшает необходимость ручного
преобразования в сервисах и контроллерах, централизуя правила
нормализации на уровне моделей данных.