Введение в class-transformer: что это и зачем нужно
class-transformer — это мощная библиотека для TypeScript и JavaScript, которая позволяет преобразовывать обычные (plain) объекты JavaScript в экземпляры классов и обратно. Она решает фундаментальную проблему: при работе с данными из API, баз данных или JSON-файлов вы получаете простые объекты без методов и типов. class-transformer «оживляет» эти данные, превращая их в полноценные объекты классов с валидацией, трансформацией и сериализацией.
Основные сценарии использования:
- Преобразование JSON из API в типизированные объекты классов — например, после получения ответа от REST API вы можете автоматически преобразовать JSON в экземпляры ваших моделей.
- Валидация и трансформация данных — с помощью декораторов можно указать, какие поля обязательны, какие нужно преобразовать (например, строку в число или дату).
- Сериализация объектов в JSON — обратное преобразование экземпляров классов в простые объекты для отправки на клиент или сохранения.
- Работа с вложенными объектами и массивами — библиотека умеет рекурсивно преобразовывать вложенные структуры данных.
class-transformer часто используется вместе с class-validator (для валидации) и популярными фреймворками, такими как NestJS, TypeORM и MikroORM.
Установка
Установка библиотеки производится через npm или yarn:
npm install class-transformer --save
Или, если вы используете yarn:
yarn add class-transformer
Для работы с декораторами в TypeScript необходимо включить поддержку экспериментальных декораторов в файле tsconfig.json:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Также рекомендуется установить reflect-metadata для корректной работы декораторов:
npm install reflect-metadata --save
И импортировать его в самом начале вашего приложения (обычно в главном файле index.ts или main.ts):
import 'reflect-metadata';
Быстрый старт с примером кода
Давайте создадим простую модель пользователя и преобразуем JSON-данные в экземпляр класса.
import { plainToClass, Expose, Type } from 'class-transformer';
import 'reflect-metadata';
// Определяем класс User
class User {
@Expose()
id: number;
@Expose()
firstName: string;
@Expose()
lastName: string;
@Expose()
@Type(() => Date)
createdAt: Date;
// Метод класса — доступен только после трансформации
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
// Пример данных из API (plain object)
const plainUser = {
id: 1,
firstName: 'Иван',
lastName: 'Петров',
createdAt: '2024-01-15T10:30:00Z'
};
// Преобразуем plain object в экземпляр класса User
const userInstance = plainToClass(User, plainUser);
console.log(userInstance instanceof User); // true
console.log(userInstance.getFullName()); // "Иван Петров"
console.log(userInstance.createdAt); // Date object: Tue Jan 15 2024 13:30:00 GMT+0300
Как видите, мы получили полноценный объект класса с методами и правильно преобразованными типами (строка даты стала объектом Date).
Основные методы и функции class-transformer
1. plainToClass
Что делает: Преобразует один или несколько простых (plain) объектов в экземпляры указанного класса. Это самый часто используемый метод.
Параметры:
cls: new (...args: any[]) => T— конструктор класса, в который нужно преобразовать.plain: T[] | T— простой объект или массив объектов.options?: ClassTransformOptions— необязательные опции (например,excludeExtraneousValues,enableCircularCheck).
Пример:
import { plainToClass } from 'class-transformer';
class Product {
id: number;
name: string;
price: number;
}
const plainProduct = { id: 1, name: 'Ноутбук', price: 75000 };
const product = plainToClass(Product, plainProduct);
console.log(product instanceof Product); // true
2. classToPlain
Что делает: Обратное преобразование — из экземпляра класса в простой объект (plain object). Полезно для сериализации перед отправкой на клиент.
Параметры:
object: T— экземпляр класса.options?: ClassTransformOptions— опции трансформации.
Пример:
import { classToPlain } from 'class-transformer';
const productInstance = new Product();
productInstance.id = 1;
productInstance.name = 'Монитор';
productInstance.price = 25000;
const plain = classToPlain(productInstance);
console.log(plain); // { id: 1, name: 'Монитор', price: 25000 }
console.log(plain instanceof Product); // false
3. serialize
Что делает: Сериализует экземпляр класса (или массив экземпляров) в JSON-строку. По сути, это комбинация classToPlain и JSON.stringify.
Параметры:
object: T | T[]— экземпляр класса или массив.options?: ClassTransformOptions— опции.
Пример:
import { serialize } from 'class-transformer';
const jsonString = serialize(productInstance);
console.log(jsonString); // '{"id":1,"name":"Монитор","price":25000}'
4. deserialize
Что делает: Десериализует JSON-строку в экземпляр класса. Обратная операция к serialize.
Параметры:
cls: new (...args: any[]) => T— класс.json: string— JSON-строка.options?: ClassTransformOptions— опции.
Пример:
import { deserialize } from 'class-transformer';
const json = '{"id":2,"name":"Клавиатура","price":5000}';
const keyboard = deserialize(Product, json);
console.log(keyboard instanceof Product); // true
console.log(keyboard.name); // "Клавиатура"
5. plainToClassFromExist
Что делает: Преобразует plain-объект в существующий экземпляр класса (обновляет его поля). Полезно для частичного обновления данных.
Параметры:
cls: new (...args: any[]) => T— класс.plain: T[] | T— данные для обновления.existingObject: T— существующий экземпляр.options?: ClassTransformOptions— опции.
Пример:
import { plainToClassFromExist } from 'class-transformer';
const existingProduct = new Product();
existingProduct.id = 1;
existingProduct.name = 'Старое название';
existingProduct.price = 100;
const updateData = { name: 'Новое название', price: 200 };
plainToClassFromExist(Product, updateData, existingProduct);
console.log(existingProduct.name); // "Новое название"
console.log(existingProduct.id); // 1 (не изменилось)
6. instanceToPlain
Что делает: Аналог classToPlain, но с улучшенной поддержкой вложенных объектов и массивов. Рекомендуется использовать вместо classToPlain в новых проектах.
Параметры:
object: T | T[]— экземпляр класса.options?: ClassTransformOptions— опции.
Пример:
import { instanceToPlain } from 'class-transformer';
const plainFromInstance = instanceToPlain(productInstance);
7. instanceToInstance
Что делает: Клонирует экземпляр класса с применением всех трансформаций. Создает новый объект того же класса.
Параметры:
object: T— исходный экземпляр.options?: ClassTransformOptions— опции.
Пример:
import { instanceToInstance } from 'class-transformer';
const clonedProduct = instanceToInstance(productInstance);
console.log(clonedProduct instanceof Product); // true
console.log(clonedProduct !== productInstance); // true (разные объекты)
8. @Expose()
Что делает: Декоратор, который указывает, что поле должно быть включено в процесс трансформации. По умолчанию все поля класса участвуют, но с помощью опций можно управлять этим.
Параметры:
options?: ExposeOptions— может содержатьname(для маппинга на другое имя в JSON),groupsи другие.
Пример:
import { Expose } from 'class-transformer';
class User {
@Expose({ name: 'user_id' })
id: number;
@Expose()
name: string;
}
const plain = { user_id: 1, name: 'Анна' };
const user = plainToClass(User, plain);
console.log(user.id); // 1 (поле id получило значение из user_id)
9. @Exclude()
Что делает: Декоратор, исключающий поле из процесса трансформации. Полезно для скрытия паролей или внутренних данных.
Параметры:
options?: ExcludeOptions— может содержатьtoClassOnlyилиtoPlainOnlyдля выборочного исключения.
Пример:
import { Exclude, Expose } from 'class-transformer';
class User {
@Expose()
username: string;
@Exclude()
password: string;
}
const user = new User();
user.username = 'ivan';
user.password = 'secret123';
const plain = classToPlain(user);
console.log(plain); // { username: 'ivan' } — password исключен
10. @Transform()
Что делает: Декоратор для кастомной трансформации поля. Позволяет применить произвольную функцию преобразования.
Параметры:
transformFn: (params: TransformFnParams) => any— функция трансформации.options?: TransformOptions— опции (например,groups).
Пример:
import { Transform } from 'class-transformer';
class Product {
@Transform(({ value }) => value.toUpperCase())
name: string;
@Transform(({ value }) => Math.round(value))
price: number;
}
const plain = { name: 'ноутбук', price: 74999.99 };
const product = plainToClass(Product, plain); Также в библиотеке
Ardalis.SmartEnum для C# (.NET): полное руководство с примерами
Работа с изображениями в C# (.NET): полное руководство
Event Bus и паттерн Observer в C++: реализация и примеры