Skip to content

How to inject method parameter #1540

Description

@imcm7

How to inject method parameter

@inject()
Class Name {

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

Activity

  1. skalinkin commented on Oct 11, 2023

    @skalinkin

    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.

  2. rsaz commented on Oct 23, 2024

    @rsaz
    Contributor

    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

  3. self-assigned this
    on Oct 23, 2024
  4. closed this as completedby moving to Done in Inversify maintenanceon Oct 23, 2024
  5. locked and limited conversation to collaborators on Oct 23, 2024
  6. converted this issue into a discussion #1592 on Oct 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions