Что такое TypeORM?

«Что такое TypeORM?» — вопрос из категории ORM, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

TypeORM — это Object-Relational Mapper (ORM) для TypeScript и JavaScript, который работает в среде Node.js. Он позволяет взаимодействовать с реляционными базами данных (такими как PostgreSQL, MySQL, MariaDB, SQLite, Microsoft SQL Server) и даже с MongoDB, используя объектно-ориентированный подход: вы работаете с классами и объектами (сущностями), а TypeORM транслирует это в SQL-запросы.

Ключевые концепции и особенности:

  • Сущности (Entities): Классы, помеченные декоратором @Entity(), которые отображаются на таблицы в БД.

    import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
    
    @Entity('users') // Имя таблицы в БД
    export class User {
      @PrimaryGeneratedColumn()
      id: number;
    
      @Column({ type: 'varchar', length: 100 })
      name: string;
    
      @Column({ unique: true })
      email: string;
    }
  • Два паттерна работы:

    1. Active Record: Сущность наследует от базового класса BaseEntity и получает методы для работы с собой (save, find, remove).
      const user = new User();
      user.name = 'Alice';
      await user.save(); // Метод доступен, если User extends BaseEntity
    2. Data Mapper: Используются отдельные классы-репозитории (Repository), которые инкапсулируют всю логику работы с сущностью. Это считается более гибким и чистым подходом.
      // В сервисе
      const userRepository = dataSource.getRepository(User);
      const newUser = userRepository.create({ name: 'Bob', email: 'bob@mail.com' });
      await userRepository.save(newUser);
  • Связи (Relations): Легко определяются через декораторы (@OneToMany, @ManyToOne, @ManyToMany, @OneToOne).

  • Миграции (Migrations): Позволяют управлять изменениями схемы базы данных в контролируемом виде.

  • Query Builder: Мощный конструктор запросов для сложных операций.

Пример использования Data Mapper в приложении на Express + TypeORM:

// user.service.ts
import { AppDataSource } from './data-source'; // Настроенный DataSource
import { User } from '../entity/User';

export class UserService {
  private userRepository = AppDataSource.getRepository(User);

  async createUser(userData: Partial<User>): Promise<User> {
    const user = this.userRepository.create(userData);
    return await this.userRepository.save(user);
  }

  async findUserByEmail(email: string): Promise<User | null> {
    return await this.userRepository.findOne({ where: { email } });
  }
}