Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"TypeError: Invalid type requested to IoC container. Type is not defined." - improve error message? #54

Open
seiyria opened this issue Oct 10, 2019 · 4 comments

Comments

@seiyria
Copy link

seiyria commented Oct 10, 2019

Been using this library for a while, and it's pretty great compared to the other IoC libraries I've seen. My only major problem is this error - I never have any idea what it's trying to inject and failing to inject. Can this error message be improved so I can track down what it's trying to inject, so I can actually fix it instead of guessing randomly?

Given some advice, I would happily implement this myself as well. I just don't know if this is something that can be done easily or where to approach it, as I've never touched the internals of a DI framework.

@thiagobustamante
Copy link
Owner

I totally agree that this message is not good. But I just don't know how to give more information.

The only place where this error is raised is:

    public static checkType(source: Object) {
        if (!source) {
            throw new TypeError('Invalid type requested to IoC ' +
                'container. Type is not defined.');
        }
    }

And checkType is called when you are trying to bind a new class to the container:

  • Container.bind(),
  • Container.to()

So, this message occurs if you call Container.bind or Container.to passing a null or undefined type.
We don't have more information than this

@Kampfmoehre
Copy link

We have a case here, where this error is not helpful at all.

We have a common base project which some of our other projects get via NPM. This project defines a BaseClass that gets some services via typescript-ioc and a Wrapper that initializes this class. The wrapper receives the base class via injection. Now in the downstream projects we extend from that base class and set our container configuration to use the extended class when asking for the base class.
This produces the error mentioned above.

Some code:
Base package baseapp.ts

import { SomeService } from "./someservice";
import { Inject } from "typescript-ioc";

export abstract class BaseApp {
  @Inject protected service1: SomeService;

  public async bootstrap() {
    // some base logic that all downstream projects need
    await this.service1.init();
    await this.customBootstrap();
  }

  protected abstract customBootstrap(): Promise<void>;
}

Base package applicationwrapper.ts

import { BaseApp } from "./baseapp";
import { Inject } from "typescript-ioc";

export class ApplicationWrapper {
  @Inject private app: BaseApp;

  public async boot() {
    // ...
    await this.app.bootstrap();
  }
}

Base package index.ts

import { BaseApp } from "./baseapp";
import { ApplicationWrapper } from "./applicationwrapper";

export { BaseApp, ApplicationWrapper };

Downstream project app.ts

import { BaseApp } from "base-package";
import { Inject } from "typescript-ioc";
import { SomeOtherService } from "./someotherservice";

export class App extends BaseApp {
  @Inject private service2: SomeOtherService;
  protected async customBootstrap(): Promise<void> {
    await this.service2.init();
  }
}

Downstream project ioc.ts

import { BaseApp } from "base-package";
import { Container } from "typescript-ioc";
import { App } from "./app";

export function configureContainer() {
  Container.bind(BaseApp).to(App);
}

Downstream project index.ts

import { ApplicationWrapper } from "base-package";
import { App } from "./app";
import { configureContainer } from "./ioc";

configureContainer();
const wrapper = new ApplicationWrapper();
wrapper.boot();

The problem occurs in the wrapper when the app Property is used for the first time in the wrapper class.

Now I 'm just guessing here, but I think the use of typescript-ioc in both packages is not working as intended. For Node the class BaseClass in the base package is somehow not the same as the imported BaseClass in the derived package. Maybe this has something to do with the way require works, putting the complete path to a module in it's name.

We tried importing the BaseClass directly via import { BaseClass } from "base-module"; as well as import the file directly like import { BaseClass } from "base-module/dist/baseclass" but non of them works.

So I have no idea, why the type is not defined in this case, but @thiagobustamante is right, somehow the source argument is undefined.

Is there anything we can change to make it work? Right now the only solution is, to not use Inject in the Wrapper, but to instantiate the App class and provide it as argument to the ApplicationWrapper. Is injecting over multiple packages supported at all?

@nemcikjan
Copy link

We have a case here, where this error is not helpful at all.

We have a common base project which some of our other projects get via NPM. This project defines a BaseClass that gets some services via typescript-ioc and a Wrapper that initializes this class. The wrapper receives the base class via injection. Now in the downstream projects we extend from that base class and set our container configuration to use the extended class when asking for the base class.
This produces the error mentioned above.

Some code:
Base package baseapp.ts

import { SomeService } from "./someservice";
import { Inject } from "typescript-ioc";

export abstract class BaseApp {
  @Inject protected service1: SomeService;

  public async bootstrap() {
    // some base logic that all downstream projects need
    await this.service1.init();
    await this.customBootstrap();
  }

  protected abstract customBootstrap(): Promise<void>;
}

Base package applicationwrapper.ts

import { BaseApp } from "./baseapp";
import { Inject } from "typescript-ioc";

export class ApplicationWrapper {
  @Inject private app: BaseApp;

  public async boot() {
    // ...
    await this.app.bootstrap();
  }
}

Base package index.ts

import { BaseApp } from "./baseapp";
import { ApplicationWrapper } from "./applicationwrapper";

export { BaseApp, ApplicationWrapper };

Downstream project app.ts

import { BaseApp } from "base-package";
import { Inject } from "typescript-ioc";
import { SomeOtherService } from "./someotherservice";

export class App extends BaseApp {
  @Inject private service2: SomeOtherService;
  protected async customBootstrap(): Promise<void> {
    await this.service2.init();
  }
}

Downstream project ioc.ts

import { BaseApp } from "base-package";
import { Container } from "typescript-ioc";
import { App } from "./app";

export function configureContainer() {
  Container.bind(BaseApp).to(App);
}

Downstream project index.ts

import { ApplicationWrapper } from "base-package";
import { App } from "./app";
import { configureContainer } from "./ioc";

configureContainer();
const wrapper = new ApplicationWrapper();
wrapper.boot();

The problem occurs in the wrapper when the app Property is used for the first time in the wrapper class.

Now I 'm just guessing here, but I think the use of typescript-ioc in both packages is not working as intended. For Node the class BaseClass in the base package is somehow not the same as the imported BaseClass in the derived package. Maybe this has something to do with the way require works, putting the complete path to a module in it's name.

We tried importing the BaseClass directly via import { BaseClass } from "base-module"; as well as import the file directly like import { BaseClass } from "base-module/dist/baseclass" but non of them works.

So I have no idea, why the type is not defined in this case, but @thiagobustamante is right, somehow the source argument is undefined.

Is there anything we can change to make it work? Right now the only solution is, to not use Inject in the Wrapper, but to instantiate the App class and provide it as argument to the ApplicationWrapper. Is injecting over multiple packages supported at all?

If you are using the library in your base project you have to reexport it and import in your downstream project. The problem importing in both projects from typescript-ioc is, that there two containers created, one for each project. We laso faced this issue and solution was creating a 'fake' path infrastructure ioc in base module which only reexports: export * from 'typescript-ioc' and then you should import from base_module/infrastructure/ioc. Hope this solves your trouble

@Kampfmoehre
Copy link

Yes I fixed some other problems by moving typescript-ioc from dependency to peer-dependency in the base project. But the problem with injecting a class that is extended in the downstream project remains.
I think the BaseApp class that I configure in the extended project is somehow not the same BaseApp class in the transpiled JavaScript in the node_modules/base-package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants