Injecting singletons in a circular manner with Inversify

Is it possible to use two singletons and enable them to call each other in the following manner?

import 'reflect-metadata';
import { Container, inject, injectable } from 'inversify';

let container = new Container();

@injectable()
class Dom {
  private domUi: DomUi;

  constructor (domUi: DomUi) {
    this.domUi = domUi;
  }
}

@injectable()
class DomUi {
  private dom: Dom;

  constructor (dom: Dom) {
    this.dom = dom;
  }
}

@injectable()
class Test {
  constructor (dom: Dom) {
    console.log(dom);
  }
}

container.bind<Dom>(Dom).toSelf().inSingletonScope();
container.bind<DomUi>(DomUi).toSelf().inSingletonScope();

const test = container.resolve(Test);

Encountering this error message:

Error: Missing required @inject or @multiInject annotation in: argument 0 in class Dom.

How can this issue be resolved? Even after trying out @inject and @multiInject, the problem persists.
Could there be a more suitable approach to tackle this conundrum from a design pattern perspective?

Answer №1

It appears that a bug has been identified, and to address it, the following workaround can be used:

import "reflect-metadata";
import { Container, inject, injectable } from "inversify";
import getDecorators from "inversify-inject-decorators";

let container = new Container();
let { lazyInject } = getDecorators(container);

@injectable()
class DomUi {
    private _dom: Dom;

    public constructor (dom: Dom) {
        this._dom = dom;
    }
}

@injectable()
class Dom {
    @lazyInject(DomUi) private domUi: DomUi;
}

@injectable()
    class Test {
    constructor(dom: Dom) {
        console.log(dom);
    }
}

container.bind<Dom>(Dom).toSelf().inSingletonScope();
container.bind<DomUi>(DomUi).toSelf().inSingletonScope();
const dom = container.resolve(Test);

A better implementation is suggested using symbols instead of classes for identification purposes:

import "reflect-metadata";
import { Container, inject, injectable } from "inversify";
import getDecorators from "inversify-inject-decorators";

let container = new Container();
let { lazyInject } = getDecorators(container);

const TYPE = {
    Dom: Symbol("Dom"),
    DomUi: Symbol("DomUi"),
    Test: Symbol("Test")
};

interface Dom {}
interface DomUi {}
interface Test {}

@injectable()
class DomUi {
    public dom: Dom;

    public constructor (
        @inject(TYPE.Dom) d: Dom
    ) {
        this.dom = d;
    }
}

@injectable()
class Dom {
    @lazyInject(TYPE.DomUi) public domUi: DomUi;
}

@injectable()
class Test {
    constructor(
        @inject(TYPE.Dom) d: Dom
    ) {
        console.log(d, d.domUi.dom);
    }
}

container.bind<Dom>(TYPE.Dom).to(Dom).inSingletonScope();
container.bind<DomUi>(TYPE.DomUi).to(DomUi).inSingletonScope();
container.bind<Test>(TYPE.Test).to(Test);
const dom = container.get(TYPE.Test);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing TS2722 alongside restrictive parameters in tsconfig

I have encountered these errors due to the presence of the strictNullChecks parameter, which is activated by the strict configuration in the tsconfig.json file. It appears that when arguments.length === 2, the ab function should be available (thanks to Fun ...

Testing Angular: How to Unit-test HttpErrorResponse with custom headers using HttpClientTestingModule

In the code snippet below, I am attempting to find a custom header on error: login(credentials: Credentials): Observable<any> { return this.http.post(loginUrl, credentials) .pipe( catchError((httpErrorResponse: HttpErrorRespo ...

Displaying error messages in Angular Material upon clicking a button

I am struggling with validation using the <mat-form-field> and <mat-error>. The validation works as expected when the user tabs out of the input without filling it. However, I'm facing a challenge in making this error show up when a button ...

The Typescript compiler is throwing an error in a JavaScript file, stating that "type aliases can only be used in a .ts file."

After transitioning a react js project to react js with typescript, I made sure to move all the code to the typescript react app and added types for every necessary library. In this process, I encountered an issue with a file called HeatLayer.js, which is ...

An exception is thrown by TypeScript's readline.createInterface function

My current project involves creating an electron app. I am facing an issue in the main.ts file where I have constructed a seemingly simple class with a constructor that is not running as expected. The problem arises when the call to readline.createInterfac ...

Is it feasible to set an empty object as the initial default value in the state of a React component?

In my React application with TypeScript, I am using "react": "^17.0.0". Here is how I define the app state: export interface IRoleState { data: API.RoleItem, menus: API.MenuItem, } When I set up the initial state like this: con ...

"Encountering a Bug in Angular 2 Related to Chart.js

I am currently in the process of developing a Twitter-style application using a Typescript/Angular2 front-end framework and a Node.js back-end. The foundation of my project is derived from Levi Botelho's Angular 2 Projects video tutorial, although I h ...

What is the best way to incorporate a @types module into a TypeScript file that is not already a module?

Setting the Stage: In the process of shifting a hefty ~3,000 line inline <script> from a web-page to a TypeScript file (PageScripts.ts) to be utilized by the page through <script src="PageScripts.js" defer></script>. This script entails ...

The side menu fails to appear when pressed

When using the push method, I am unable to see the side menu. However, it works fine with the setRoot navigation. How can I resolve this issue and display the side menu when using the push method? dashboard.html <ion-col col-9> <ion-searchbar ...

TypeScript Compile Error: The property is not available in the 'IStateParamsService' type

My client project heavily utilizes TypeScript. Currently, I am encountering a technical issue. Within my HTML code, I have an anchor tag as shown below: <a class="btn btn-default mrm" ui-sref="course-detail({courseId: '{{c.Id}}'})">Detail ...

Utilize Dinero.js to implement currency formatting for input fields in React applications

I am currently working on a form in React that requires certain input fields to be formatted as money currency. These inputs should be prefixed with the dollar sign ($), include commas for thousands separation, and have exactly two decimal points. During ...

How can I configure React Router V6 to include multiple :id parameters in a Route path, with some being optional?

Currently, I am utilizing react-router@6 and have a Route that was previously used in V5. The route is for vehicles and always requires one parameter (:id = vehicle id), but it also has an optional second parameter (:date = string in DD-MM-YYYY format): &l ...

Exploring the incorporation of interfaces into Vue.js/Typescript for variables. Tips?

I have an interface:   export interface TaskInterface{ name: string description1: string time: string } and a component import { TaskInterface } from '@/types/task.interface' data () { return { tasks: [ { name: 'Create ...

Launching a Material UI Modal nested within a parent component

I have a table displaying various teams. Each row in the table has a menu option that, when clicked, should open either a modal or a dialog box. I want to keep the table, menu functionality, and modals as separate components for better organization. Here&a ...

Is it Possible to Use Guice Constructor Injection without Annotations?

Is there any assistance available for implementing Guice without the use of annotations? public interface IAnimal { void makeNoise(); } public interface IVehicle { int getWheelCount(); } import org.apache.commons.logging.Log; public class Car i ...

Using command line arguments in a Tauri project with a Next.js frontend

I am utilizing Tauri.JS in conjunction with Next.js. In this scenario, I need to execute the console command: npm run tauri dev --<argument name>=<some value>. Afterwards, I should be able to access the value of the argument in my JavaScript ...

Setting default values on DTO in NestJS can be done by using the DefaultValue decorator provided

import { IsString, IsNumber, IsOptional, IsUUID, Min, Max } from 'class-validator'; import { Transform } from 'class-transformer'; export class QueryCollateralTypeDto { @Transform(({ value }) => parseInt(value)) @IsNumber() @I ...

Ensure that the variable is not 'undefined' and that it is a single, clean value

In my node backend project, I've encountered a situation with my TypeScript code where a variable occasionally prints as the string 'undefined' instead of just being undefined. Is there a more elegant way to check that the variable is not eq ...

Performing a conditional query on a Many-to-Many relationship in TypeORM

Operating under a many-to-many relationship between Category and Product entities In need of filtering products based on category ID Attempted to implement the following code after referring to some examples, but encountered difficulties in making it fun ...

Enhancing JavaScript with TypeScript: implementing functional mixins

I'm in the process of creating functional mixins using TypeScript. Below is the code I have written so far: const flying = (o: object) => { let isFlying = false; return Object.assign({}, o, { fly() { isFlying = true; return thi ...