tsyringe — внедрение зависимости с помощью перегруженного конструктора

#javascript #node.js #typescript #dependency-injection #typeorm

#javascript #node.js #typescript #внедрение зависимостей #typeorm

Вопрос:

Привет, друзья, как у вас дела?

Я пытаюсь сделать что-то другое, я не знаю, отличается ли это от самой концепции, но это помогло бы мне достичь того, что я пытаюсь сделать элегантным способом.

Я использую шаблон репозитория, и в реализации я хочу использовать перегруженный конструктор и использовать необязательный аргумент, в основном передавая некоторую дополнительную информацию, когда это необходимо.

Проблема в том, что он отлично работает, когда конструктор пуст, но к моменту изменения подписи для получения еще одного аргумента TSYSRINGE выдает execuption.

Я действительно думаю, что мне не хватает чего-то действительно простого, но я не могу понять, чего. Не могли бы вы, пожалуйста, помочь мне в этом? Спасибо

ОШИБКА:

 Error: Cannot inject the dependency at position #0 of "ListProjectsServices" constructor. Reason:
    TypeInfo not known for "ProjectsRepository"
  

Контроллер

 export default class ProjectsController {
  public async index(request: Request, response: Response): Promise<void> {
    const listProjectsServices = container.resolve(ListProjectsServices);
    const projects = await listProjectsServices.execute();
    response.json(projects);
  }

  

Обслуживание

 @injectable()
export default class ListProjectsServices {

  constructor(
    @inject('ProjectsRepository')
    private ProjectsRepository: IProjectsRepository,
  ) {}

  public async execute(): Promise<Projects[]> {
    const ProjectsList = await this.ProjectsRepository.findAllProjects();
    return ProjectsList;
  }
}
  

Контейнер — для создания токена внедрения

 
container.registerSingleton<IProjectsRepository>(
  'ProjectsRepository',
  ProjectsRepository,
);

  

Репозиторий — обратите внимание на аргумент extra_details в конструкторе

после его добавления возникает проблема

 
@EntityRepository(Projects)
export default class ProjectsRepository implements IProjectsRepository {
  private ormRepository: Repository<Projects>;

  constructor(extra_details?: object) {
    this.ormRepository = getRepository(Projects);
  }
[...]
  

Комментарии:

1. Эй, приятель, ты решил это?

2. Нет, на самом деле, мне пришлось изменить стратегию.

Ответ №1:

Сегодня я столкнулся с той же проблемой. Прочитайте эту статью о циклических зависимостях. Он говорит нам использовать функцию задержки, импортированную из tsyringe. В статье он говорит нам использовать задержку внутри конструктора. Но вы, как и я, напрямую отправляете не объект при внедрении, а зарегистрированный ключ. Затем вы должны использовать задержку в вашем файле контейнера, вокруг объекта репозитория попробуйте это:

 import { container, delay } from 'tsyringe';

container.registerSingleton<IProjectsRepository>(
  'ProjectsRepository',
  delay(() => ProjectsRepository),
);
  

Вставьте задержку во все ваши инъекции, которые зависят от асинхронного репозитория

Это также может быть ошибкой в seo или в файле config.json в свойстве entities. Убедитесь, что путь указывает на ваши объекты:

 "entities": [
  "./src/modules/**/infra/typeorm/entities/*.ts"
],
  

Комментарии:

1. Это действительно звучит интересно, я обязательно попробую. Звучит элегантно и эффективно! Спасибо, мой друг!

Ответ №2:

Здесь у нас была та же проблема, и мы не хотели использовать функцию задержки в контроллере, потому что мы нарушили бы принцип внедрения зависимостей… Один из способов решить проблему — импортировать ваш файл «контейнера» в основной файл проекта, в нашем случае под названием «server.ts» и установить библиотеку под названием «reflect-metadata».

server.ts:

 import * as dotenv from 'dotenv';

dotenv.config();

import express from 'express';
import 'express-async-errors';
import 'reflect-metadata'; // here is reflect-metadata import!
import config from './config/application';
import './infra/container'; // here is container import!
import { errorHandler } from './infra/http/middlewares/errorHandler';
import useSwagger from './infra/http/middlewares/swagger';
import { routes } from './infra/http/routes';
import { morganMiddleware } from './infra/logging/morgan';

export const app = express();

app.use(morganMiddleware);
app.use(express.json());
app.use(`${config.prefix}/api`, routes);
app.use(`${config.prefix}`, express.static('public'));
useSwagger(`${config.prefix}/api/docs`, app);
app.all(`${config.prefix}`, (_, res) => res.redirect(`${config.prefix}/api/docs`));
app.use(errorHandler);
  

контейнер/index.ts:

 import { container } from 'tsyringe';
import { RecurrenceNotificationUseCase } from '../../application/useCases/RecurrenceNotificationUseCase';
import { PubSubImplementation } from '../pubsub/PubSubImplementation';

container.registerSingleton('IPubSub', PubSubImplementation);
container.registerSingleton('IRecurrenceNotificationUseCase', RecurrenceNotificationUseCase);