question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot @Inject service into plain class

See original GitHub issue

I am trying to use a utility service ( winston logger) in a plain TypeScript class. I can only get the instance of the service via Container.get(LoggerService). Using anything else like custom decorators @Logger() or @Inject(), constructor injection or property injection. All those ways lead to this.logger being undefined inside the Game class. Inside the Application, which is a service, the logger works perfectly fine. For minimal reproduction i have created this repo: https://github.com/drdreo/type-di-bug

Game instantiated like:

@Service()
export class Application {

    constructor(
        @Inject(ExpressServerImpl) private readonly server: IServer,
        @Logger() private readonly logger: ILogger,
        private readonly envService: EnvService
    ) {   }

    public readonly start = () => {
        const port = this.envService.Port;
        this.server.start(port);
        this.logger.info(`Server listening at port ${port}`);
        this.logger.info(`App running in [${this.envService.Env}] mode`);

        const game = new Game(["foo"]);
    };
}
import {ILogger} from "./interfaces/ILogger";

export class Game {
    @Logger() private readonly logger: ILogger;
    constructor(private players: any) {
        // FAILS HERE, this.logger is undefined
        this.logger.debug("Game has started");
    }
}


How can i get the service injected into plain classes?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:3
  • Comments:7

github_iconTop GitHub Comments

2reactions
jharrilimcommented, May 18, 2019

This seems to be the normal behaviour as far as runtime DI frameworks go.

In order for DI to work, it generally must follow a couple of guidelines:

  • Your service is registered with the IoC container
  • You have a class that expects to receive this service (via constructor, or by annotating a field)
  • You tell your container to instantiate the class for you

The 3rd part is crucially important, as calling new yourself will not inject dependencies. This can only be done with compile-time DI frameworks, such as Wire (Go) or Dagger (Java). Frameworks like this use code generation to achieve this.

The other frameworks that use reflection work the same way as TypeDI by using runtime metadata. ASP.NET Core’s DI and Spring, and Angular. check out the Angular DI for an example of this:

https://github.com/angular/angular/blob/master/packages/core/test/di/reflective_injector_spec.ts

Notice how similar this is to TypeDI, although it is something that you do not actually notice when using Angular. In Angular, they have an entire framework dedicated to creating components. Their framework is what calls the injector.get() method, while the end user only worries about creating and registering their components, not instantiating them.

Angular does seem to have a way of registering classes without using annotations by using the static block. You can find examples of that here:

https://github.com/angular/angular/blob/master/packages/core/test/di/r3_injector_spec.ts

Long story short: You need to use Container.get instead of calling new. You should not need to do this a lot since Container.get will inject nested services.

0reactions
github-actions[bot]commented, Jul 31, 2020

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to inject service into class (not component) - Stack Overflow
Injections only works with classes that are instantiated by Angulars dependency injection (DI). You need to. add @Injectable() to MyClass and ...
Read more >
Angular Dependency Injection: Complete Guide
The best way to understand dependency injection in Angular, is to take a plain Typescript class without any decorators applied to it, ...
Read more >
Configuring dependency providers - Angular
The Creating and injecting services topic describes how to use classes as dependencies. ... If you specify the service class as the provider...
Read more >
How to use dependency injection with strings and numbers in ...
You're probably familiar with dependency injection using classes, but what about using strings, numbers, booleans, or any other object?
Read more >
Crux Dependency Injection - The Apache Software Foundation!
The IoC Container of Crux is the BeanProvider class. ... Due to restrictions imposed by runtimes, Crux cannot inject into private , protected...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found