РекомендуетсяNestJS 11TypeScript

NestJS: модули, имена и внедрение зависимостей

Собирайте функцию приложения через Nest module: controller обрабатывает транспорт, provider внедряется container, exports задает публичные зависимости. Имена и пути должны показывать роль без обязательных лишних слоев.

Опубликовано Проверено Изменено

Плохо

const orders = new OrdersService(new DatabaseClient());
@Controller('orders')
export class OrdersController {
  @Get()
  list() { return orders.list(); }
} // Жизненный цикл и зависимости обходят Nest container.

Хорошо

import { Controller, Get, Injectable, Module } from '@nestjs/common';
 
@Injectable()
export class OrdersService {
  list(): ReadonlyArray<{ id: number }> {
    return [{ id: 1 }];
  }
}
 
@Controller('orders')
export class OrdersController {
  constructor(private readonly orders: OrdersService) {}
  @Get()
  list() { return this.orders.list(); }
}
 
@Module({
  controllers: [OrdersController],
  providers: [OrdersService],
  exports: [OrdersService],
})
export class OrdersModule {}

Почему это важно

Container может управлять жизненным циклом, scopes и тестовыми подменами только для зарегистрированных providers. Ручное создание зависимостей в глобальном коде скрывает их настройку и часто создает отдельные экземпляры ресурсов.

Когда применять

NestJS 11 с TypeScript и включенными настройками decorators/metadata по шаблону выбранной версии. Пример в одном фрагменте; обычно файлы называются orders.module.ts, orders.controller.ts, orders.service.ts, классы — PascalCase, методы — camelCase. Это соглашение проекта/CLI, не ограничение файловой системы языка.

OrdersModule включен в imports корневого модуля. Другой модуль, которому нужен OrdersService, импортирует OrdersModule; provider экспортируется только если действительно нужен снаружи. Не повторяйте регистрацию одного stateful provider в каждом module, если нужен общий экземпляр.

TypeScript interface не существует в runtime: для interface-зависимости нужен явный injection token и binding. Concrete-классу отдельный token обычно не нужен. Scope request выбирают по причине; singleton не хранит изменяемое состояние текущего пользователя.

DTO и ValidationPipe защищают вход, guards — доступ; это другие границы. Изолируйте бизнес-операцию при необходимости, но не создавайте обязательные Repository/Manager/Facade для простого controller. Расширение imports для ESM зависит от moduleResolution и версии сборки, поэтому не смешивайте шаблоны разных профилей.

Кто что делает

Человек

Выбирает границы modules и действительно публичные providers.

AI-агент

Проверяет imports/providers/exports, runtime tokens и scope; сохраняет транспортные DTO отдельно от доменного состояния.

Как проверить у себя

Вход и действиеОжидаемый результатСвидетельство
Bootstrap корневого module и GET /ordersProvider разрешен, маршрут возвращает контрактный ответNest TestingModule и HTTP
Удален import/exports нужного moduleЗависимость не разрешается; проверка ловит конфигурациюНегативный bootstrap
Provider заменен в тестеController использует подмену через containeroverrideProvider и наблюдение вызова
Два пользователя одновременноSingleton не смешивает request stateКонкурентный сценарий

Компиляция TypeScript без bootstrap Nest не подтверждает graph providers.

ПервоисточникиИстория изменений на GitHub

Дата проверки отражает содержательную сверку. Синхронизация сайта не обновляет её автоматически.