2

I am trying to achieve dependency injection on my node project via inversify.

I have a kernel config like this: inversify.config.ts

import "reflect-metadata";
import {Kernel, interfaces} from "inversify";

import {Config} from "./config";
import {Collection} from "./collection";

let kernel = new Kernel();

kernel.bind<Config>("Config").to(Config).inSingletonScope();
// kernel.bind<interfaces.Newable<Collection>>("Collection").toConstructor<Collection>(Collection);
// it works without the line above

A class: config.ts

import {injectable} from "inversify";
@injectable()
export class Config {
  constructor() {}
}

A class with property DI collection.ts

import {injectable} from "inversify";
import getDecorators from "inversify-inject-decorators";
import kernel from "../inversify.config";
let {lazyInject} = getDecorators(kernel);

@injectable()
export class Collection {
  @lazyInject(Config)
  private Config: Config;

  constructor(a: string, b: string) {}
}

Everything works as expected if I don't bind a class with property injection. When I try to bind a class with @lazyInject as shown in the example

kernel.bind<interfaces.Newable<Collection>>("Collection").toConstructor<Collection>(Collection);

import line in inversify.config.ts starts processing Collection.ts and the line

import kernel from "../inversify.config";`

in it. However as we arrived Collection.ts while we already processing inversify.config.ts file line

import kernel from "../inversify.config";`

somehow returns undefined making kernel undefined for Collection class. Therefore @lazyInject DI fails.

Eventually when I try to read Config in Collection it fails with:

TypeError: Cannot read property 'get' of undefined
    at resolve (node_modules/inversify-inject-decorators/lib/decorators.js:24:30)
    at Category.getter (node_modules/inversify-inject-decorators/lib/decorators.js:6:47)

I wonder if there is a way to accomplish binding a class with property DI via @lazyInject without moving kernel definition into the same file with one of the classes. I am looking for a way to import kernel as it is now, but make it work properly.

Umut Benzer
  • 3,476
  • 4
  • 36
  • 53

1 Answers1

5

Your problem is that you have a circular dependency:

enter image description here

I'm going to change your code and add a couple of additional files. Nothe that the he file types.ts is not needed but it is recommended to keep all your type identifiers in one single location.

After changing your code the dependency diagram will change to the following:

enter image description here

As you can se we have eliminated the circular dependency.

inversify.config.ts

import "reflect-metadata";
import {Kernel, interfaces} from "inversify";
import getDecorators from "inversify-inject-decorators";
import { makeProvideDecorator } from "inversify-binding-decorators";

let kernel = new Kernel();
let {lazyInject} = getDecorators(kernel);
let provide = makeProvideDecorator(kernel);

export { lazyInject, provide };

types.ts

let TYPES = {
  Config: "Config",
  Collection: "Collection",
};

export default TYPES;

config.ts

import { provide } from "../inversify.config";
import TYPES from "./types";

@provide(TYPES.Config)
export class Config {
  constructor() {}
}

export default Config;

collection.ts

import { lazyInject, provide } from "../inversify.config";

@provide(TYPES.Collection)
export class Collection {
  @lazyInject(TYPES.Config)
  private Config: Config;
  constructor(a: string, b: string) {}
}

export default Collection;

main.ts

You need to import all your dependencies when they are imported @provide is executed and then bindings are generated.

import Config from "./lib/config";
import Collection from "./models/collection";

//...

We have been able to eliminate the circular dependency using the @provide decorator from inversify-binding-decorators.

Remo H. Jansen
  • 23,172
  • 11
  • 70
  • 93
  • I had issues when not doing a "export default" for my identifiers as then the TYPES will be undefined. I don't get why it only works with a 'default' export? Does this have something to do with metadata generation? – Marc May 11 '18 at 08:24