inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.34k stars 719 forks source link

injecting a property #828

Closed OmarOufDev closed 6 years ago

OmarOufDev commented 6 years ago

trying to inject a component as a property . works in a file. just not the other( the injected property is undefined. ) I used the example on the readme of inversifyJS. and kept adding my module file by file while making sure everything is still running. when i added "Utilities" it gets injected properly in 1 file but not the other. not sure why.

sorry for the formating. tried as best as i could.

Steps to Reproduce (for bugs)

the file that injection works in. when i call util() . this.utilities ( is defined ).

import { injectable, inject, interfaces } from "inversify";
import { Warrior } from "./IWarrior";
import { TYPES } from "./Misc/types";
import { ICustomError } from "./Errors/ICustomError";
import { ErrorCategory } from "./Errors/CustomError";
import { IRespawnListLogic } from "./Logic/RespawnList/IRespawnListLogic";
import { IUtilities } from "./Misc";

@injectable()
export class Ninja implements Warrior {
    @inject(TYPES.ICustomError) private _customError: interfaces.Newable<ICustomError>;
    @inject(TYPES.IRespawnListLogic) private _IRespawnListLogic: IRespawnListLogic;
    @inject(TYPES.IUtilities) private utilities: IUtilities;
    public util() {
        return this.utilities.for("bla","bla").exists();
    }
    public error() { return new this._customError(ErrorCategory.Conflict,"Error Message").logError(); };
    public resp() {
        this._IRespawnListLogic.addEntry("id","name");
        const option = { enabled: false };
        this._IRespawnListLogic.setDefaultOptions(option);
        this._IRespawnListLogic.addEntry("id2","name2");
        this._IRespawnListLogic.saveConfigration();
        return this._IRespawnListLogic.getEntries();
    };
}

file where inject results in an undefined component

import { injectable, inject } from "inversify";
import { TYPES } from "../Misc/types";
import { IUtilities } from "../Misc";
import { IOptionsVerification } from "./IOptionsVerification";

@injectable()
export class OptionsVerification implements IOptionsVerification {

    @inject(TYPES.IUtilities)
    private utilities: IUtilities;

    constructor(private options: any) {
    }
    validate() {
        this.utilities.for(this.options, "options").exists();
        const newModel: any = {};
        if (this.options.enabled) {
            newModel.enabled = this.utilities.for(this.options.enabled, "enabled").toBoolean();
        }
        if (this.options.maxTime) {
            this.utilities.for(this.options.maxTime, "maxTime").isHour();
            newModel.maxTime = new Date(0, 0, 0, Number(this.options.maxTime), 0, 0, 0);
        }
        if (this.options.sameUserQueue) {
            newModel.sameUserQueue = this.utilities.for(this.options.sameUserQueue, "sameUserQueue").toBoolean();
        }

        this.utilities.for(newModel, "options").isObjectEmpty();
        return newModel;
    }
}

bootfile just for testing.

import "reflect-metadata";
import { myContainer } from "./Misc/inversify.config";
import { TYPES } from "./Misc/types";
import { Warrior } from "./IWarrior";
import { OptionsVerification } from "./Logic/OptionsVerification";

const ninja = myContainer.get<Warrior>(TYPES.Warrior);

console.log(ninja.util());

ninja.error();

const optionsVerification = new OptionsVerification({enabled: "false"}).validate();
console.log(optionsVerification);

console.log(ninja.resp());

TYPES file.

const TYPES = {
    Warrior: Symbol.for("Warrior"),
    Weapon: Symbol.for("Weapon"),
    ThrowableWeapon: Symbol.for("ThrowableWeapon"),
    ICustomError: Symbol.for("ICustomError"),
    IRespawnListLogic: Symbol.for("IRespawnListLogic"),
    IUtilities: Symbol.for("IUtilities"),
    IOptionsVerification: Symbol.for("IOptionsVerification"),
};

export { TYPES };

inversify.config.file

// file inversify.config.ts

import { Container, injectable, interfaces } from "inversify";
import { TYPES } from "./types";
import { Warrior } from "../IWarrior";
import { Ninja } from "../Warrior";
import { ICustomError, CustomError } from "../Errors/";
import { RespawnListLogic, IRespawnListLogic, IOptionsVerification, OptionsVerification } from "../Logic/";
import { IUtilities } from "./IUtilities";
import { Utilities } from "./Utilities";

const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);
myContainer.bind<interfaces.Newable<ICustomError>>(TYPES.ICustomError).toConstructor<ICustomError>(CustomError);
myContainer.bind<IUtilities>(TYPES.IUtilities).to(Utilities);
myContainer.bind<IRespawnListLogic>(TYPES.IRespawnListLogic).to(RespawnListLogic);
myContainer.bind<IOptionsVerification>(TYPES.IOptionsVerification).to(OptionsVerification);

export { myContainer };

package.json

{
  "name": "inversifyexmapleinject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc",
    "test": "npm run build && mocha --recursive ./test"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "inversify": "^4.11.1",
    "mocha": "^5.0.4",
    "node": "^9.8.0",
    "reflect-metadata": "^0.1.12"
  },
  "devDependencies": {
    "@types/mocha": "^2.2.48",
    "@types/node": "^9.4.7",
    "tslint": "^5.9.1"
  }
}

Your Environment

Stack trace

    this.utilities.for(this.options, "options").exists();
                   ^

TypeError: Cannot read property 'for' of undefined at OptionsVerification.validate (E:\TypescriptTutorial\InversifyExmapleInject\Logic\OptionsVerification.js:19:24) at Object. (E:\TypescriptTutorial\InversifyExmapleInject\boot.js:10:95) at Module._compile (module.js:643:30) at Object.Module._extensions..js (module.js:654:10) at Module.load (module.js:556:32) at tryModuleLoad (module.js:499:12) at Function.Module._load (module.js:491:3) at Function.Module.runMain (module.js:684:10) at startup (bootstrap_node.js:187:16) at bootstrap_node.js:608:3

dcavanagh commented 6 years ago
const optionsVerification = new OptionsVerification({enabled: "false"}).validate();

does not invoke anything in inversify. For the dependencies to be fulfilled you need to get the optionsVerification from the container.

Try

 const optionsVerification = myContainer.get< IOptionsVerification >(TYPES. IOptionsVerification);