Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

How to inject method parameter #1540

Closed
imcm7 opened this issue Oct 6, 2023 · 2 comments
Closed

How to inject method parameter #1540

imcm7 opened this issue Oct 6, 2023 · 2 comments
Assignees

Comments

@imcm7
Copy link

imcm7 commented Oct 6, 2023

How to inject method parameter

@inject()
Class Name {

    doSomething(
        @inject() test: string
    ) {
        console.log(string);
    }
@skalinkin
Copy link

This question appears to be out of context. The primary role of a DI (Dependency Injection) container is to inject dependencies into a constructor rather than injecting parameters into arbitrary functions. It is highly likely that you're attempting to achieve a goal that this library was not designed for.

@rsaz
Copy link
Contributor

rsaz commented Oct 23, 2024

Hi @skalinkin well said, you're correct. I will add to your answer few more things to make sure it covers all the aspect of IoC in general as well as exclusively for Inversify, so the next one to ask about this can refer to this content.

Hi @imcm7

In the example provided, you are attempting to use @inject() decorator on a method parameter inside a method (not the constructor), which is not supported by InversifyJS and in my other DI systems. Inversify primarly focused on constructor-based injection and property injection

Constructor Injection

@injectable()
class A {
    constructor(@inject("B") private b: B) {}
}

// Or
class B {
 constructor(private c: C) {}
}

Property Injection

@injectable()
class A {
    @inject("B") private b: B;
}

Why Method Parameter Injection Is Problematic:

  • InversifyJS manage object lifecycles and dependency resolution at the class level, typically focusing on constructors or properties. Injecting into individual method parameters, particularly for arbitrary methods (not constructors), can lead to unpredictable behavior;
  • Method calls might happen outside the framework's lifecycle control. There would be ambiguity in determining when and how these dependencies should be injected, particularly if the method is called multiple times with different arguments.

Another point that you have not asked but your code is trying to do is inject primitive types, and let me elaborate this a bit more for you:

Inject Primitive types

Injecting primitive types such as @inject() test: string is a less common practice in DI's compared to injecting objects, services, or class instances. I recognize that exists cases where primitive injection is necessary, for example when configuration specific values like API keys, settings, or constant are required in your use case.

Inversify is so feature rich that also handles this use case, you can inject primitives in constructors or as properties as well, here is an example:

Via Constructor

import "reflect-metadata";

import { injectable, inject, Container } from "inversify";

const TYPES = {
    apiKey: Symbol.for("apiKey"),
};

@injectable()
class ApiService {
    constructor(@inject(TYPES.apiKey) private apiKey: string) {}

    fetchData() {
        console.log(`Fetching data using API key: ${this.apiKey}`);
    }
}

const container = new Container();
container.bind<ApiService>(ApiService).toSelf();
container.bind<string>(TYPES.apiKey).toConstantValue("my-secret-api-key");

const apiService = container.get(ApiService);
apiService.fetchData();

Via property

@injectable()
class ApiService {
    @inject(TYPES.apiKey) private apiKey!: string;

    fetchData() {
        console.log(`Fetching data using API key: ${this.apiKey}`);
    }
}

With every super power comes some points that needs to be taken in consideration when using primitive injection.
Three majors issues I would highlight are:

1 - The overhead, using the DI system for a simple primitive that don't need management or change dynamically
2 - Overuse, you may end managing a bunch of primitives, task become cumbersome
3 - Type safety, since TypeScript does not enforce strict typing on symbols and strings used as service identifiers, you could introduce mistyped identifiers or mismatches between bindings and injected values.

I hope you have a clear understanding about your request now, next time try to explain a bit better your goals, use cases, so we can be more efficient on resolving the matter.

Regards

@rsaz rsaz self-assigned this Oct 23, 2024
@rsaz rsaz closed this as completed by moving to Done in Inversify maintenance Oct 23, 2024
@inversify inversify locked and limited conversation to collaborators Oct 23, 2024
@rsaz rsaz converted this issue into discussion #1592 Oct 23, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
Status: Done
Development

No branches or pull requests

3 participants