Dynamic Dependency injection with Typescript using tsyringe

5.7k views Asked by At

I am trying to build and example to understand how the DI framework/library works, but i am encountering some problems.

I have this interface with two possible implementations:

export interface Operation {
    calculate(a: number, b: number): number;
}

sub.ts

import { Operation } from "./operation.interface";

export class Sub implements Operation {
    calculate(a: number, b: number): number {
        return Math.abs(a - b);
    }
}

sum.ts

import { Operation } from "./operation.interface";

export class Sum implements Operation {
    calculate(a: number, b: number): number {
        return a + b;
    }

}

calculator.ts

import { Operation } from "./operation.interface";
import {injectable, inject} from "tsyringe";

@injectable()
export class Calculator {
    constructor(@inject("Operation") private operation?: Operation){}

    operate(a: number, b: number): number {
        return this.operation.calculate(a, b);
    }
}

index.ts

import "reflect-metadata";
import { container } from "tsyringe";
import { Calculator } from "./classes/calculator";
import { Sub } from "./classes/sub";
import { Sum } from "./classes/sum";

container.register("Operation", {
    useClass: Sum
});

container.register("OperationSub", {
    useClass: Sub
});

const calculatorSum = container.resolve(Calculator);

const result = calculatorSum.operate(4,6);
console.log(result);

// const calculatorSub = ???

is there a way where I could have two calculators with different behaviours or am I doing it completely wrong?

1

There are 1 answers

0
Estus Flask On BEST ANSWER

Since OperationSub isn’t used anywhere, it cannot affect injected Operation value.

Calculators with different dependency sets should be represented with multiple containers. Summing calculator can be considered a default implementation and use root container, or both implementations can be represented by children containers while root container remains abstract.

// common deps are registered on `container`
const sumContainer = container.createChildContainer();
const subContainer = container.createChildContainer();

sumContainer.register("Operation", { useClass: Sum });  
subContainer.register("Operation", { useClass: Sub });

const calculatorSum = sumContainer.resolve(Calculator);
const calculatorSub = subContainer.resolve(Calculator);