Inversifyjs: Undefined @inject() properties in child class from factory

Created on 29 Oct 2017  路  2Comments  路  Source: inversify/InversifyJS

Given a parent class and a child class that are both @injectable() with an @inject() member each...

@injectable()
export abstract class ParentStore {
    @inject(TYPES.StoreFactory)
    protected readonly storeFactory: StoreFactory;
}
@injectable()
export class ChildStore extends ParentStore {
    @inject(TYPES.Logger)
    public readonly logger: Logger;
}

...and a class that creates new instances of the ChildStore using an Inversify Container...

export class StoreFactory {
    public constructor(private readonly container: Container) { }

    public create(): ChildStore {
        return this.container.get<() => ChildStore>(TYPES.ChildStore)();
    }
}

...and a main that binds ChildStore to a simple factory method...

const container = new Container();

container.bind(TYPES.Logger).to(Logger);
container.bind(TYPES.StoreFactory).toConstantValue(new StoreFactory(container));
container
    .bind(TYPES.ChildStore)
    .toFactory(
        () =>
            () => new ChildStore());

const storeFactory = new StoreFactory(container);
const childStore = storeFactory.create();

childStore.logger.log("Why am I undefined?");

Expected Behavior

...when we create a new ChildStore instance, we expect that the logger should be injected.

Current Behavior

It's undefined instead.

Steps to Reproduce (for bugs)

  1. git clone https://github.com/JoshuaKGoldberg/inversiwat && cd inversiwat && npm i && tsc
  2. node lib/index.js

Context

In a more complex application, the goal is to allow the factory to create different child stores depending on POJO models passed into the factory (see an earlier inversiwat commit). Stores can then create child stores dynamically using DI based on their models.

Your Environment

  • Version used: 4.3.0
  • Environment name and version (e.g. Chrome 39, node.js 5.4): Node 8.0.0
  • Operating System and version (desktop or mobile): Windows 10 Desktop
  • Link to your project: https://github.com/JoshuaKGoldberg/inversiwat

Most helpful comment

This is expected. Inversify will resolve dependencies when objects are instantiated via the container. In this case, the factory method that you are binding here:

container
    .bind(TYPES.ChildStore)
    .toFactory(
        () =>
            () => new ChildStore());

is creating a ChildStore via its constructor, instead of through the container. What you want is probably:

// Bind the ChildStore class
container.bind(TYPES.ChildStore).toFactory(ChildStore);

// Bind the factory
container
    .bind(TYPES.ChildStoreFactory)
    .toFactory(
        () =>
            () => container.get(TYPES.ChildStore));

All 2 comments

This is expected. Inversify will resolve dependencies when objects are instantiated via the container. In this case, the factory method that you are binding here:

container
    .bind(TYPES.ChildStore)
    .toFactory(
        () =>
            () => new ChildStore());

is creating a ChildStore via its constructor, instead of through the container. What you want is probably:

// Bind the ChildStore class
container.bind(TYPES.ChildStore).toFactory(ChildStore);

// Bind the factory
container
    .bind(TYPES.ChildStoreFactory)
    .toFactory(
        () =>
            () => container.get(TYPES.ChildStore));

Thanks so much @sleepysort!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

remojansen picture remojansen  路  3Comments

stjepangolemac picture stjepangolemac  路  5Comments

jshearer picture jshearer  路  4Comments

codyjs picture codyjs  路  3Comments

Deviad picture Deviad  路  3Comments