Inversifyjs: How to bind a singleton for two different interfaces

Created on 20 Nov 2018  路  6Comments  路  Source: inversify/InversifyJS

Hi. I have a class, implementing multiple interfaces:

export class InMemoryFoodLogRepository implements IAddFoodLog, IGetFoodLogs {
}

This is a repository for, obviously, some food logs. So it should be a singleton (or else would insert everything happily and forget about them in a second). with below code

container.bind<IAddFoodLog>(TYPES.AddFoodLog).to(InMemoryFoodLogRepository).inSingletonScope();

I was able to use IAddFoodLog interface consistently and things will be saved in InMemoryFoodLogRepository. But when I want to fetch them with IGetFoodLogs interface, I find that inversify will create another instance of InMemoryFoodLogRepository for the new interface.

container.bind<IAddFoodLog>(TYPES.AddFoodLog).to(InMemoryFoodLogRepository).inSingletonScope();
container.bind<IGetFoodLogById>(TYPES.GetFoodLogById).to(InMemoryFoodLogRepository).inSingletonScope();

So how could I do this?

Most helpful comment

What I currently do, but which seems a little ugly, is the following:

container
  .bind<IAddFoodLog & IGetFoodLogById>(TYPES.AddFoodLog)
  .to(InMemoryFoodLogRepository).inSingletonScope();
const foodLogInstance = container.get<IAddFoodLog & IGetFoodLogById>(TYPES.AddFoodLog);
container
  .bind<IGetFoodLogById>(TYPES.GetFoodLogById)
  .toConstantValue(foodLogInstance);

All 6 comments

What I currently do, but which seems a little ugly, is the following:

container
  .bind<IAddFoodLog & IGetFoodLogById>(TYPES.AddFoodLog)
  .to(InMemoryFoodLogRepository).inSingletonScope();
const foodLogInstance = container.get<IAddFoodLog & IGetFoodLogById>(TYPES.AddFoodLog);
container
  .bind<IGetFoodLogById>(TYPES.GetFoodLogById)
  .toConstantValue(foodLogInstance);

To impelement SOLID and espetially Interface segregation it would be nice to have such a feature.

const A = Symbol("A");
interface A {
  fnA(): void;
}
const B = Symbol("B");
interface B {
  fnB(): void;
}

class ComplexLegacyAB implements A, B {
  // ...
}

// in module registration
// internal
bind<ComplexLegacyAB>(ComplexLegacyAB).toSelf().inSingletonScope();

// exposed
bind<A>(A).to(ComplexLegacyAB); // should poitn to the same singleton;
bind<B>(B).to(ComplexLegacyAB); // should poitn to the same singleton;

Now I have to create implementations for A and B which delegates the calls to ComplexLegacyAB what is annoying espetially when there are dozen of implemented interfaces.
If I could inject the ComplexLegacyAB instance by the interface it would allow me to step by step separate the legacy code.

Have you tried using transitive bindings?

Have you tried using transitive bindings?

@bodograumann - can you please give an example of how the code you posted on the 9th Jan would look using transitive bindings? Thank you

@mcshaz, of the top of my head, it should work like this:

container
  .bind<IAddFoodLog & IGetFoodLogById>(TYPES.AddFoodLog)
  .to(InMemoryFoodLogRepository)
  .inSingletonScope();
container
  .bind<IGetFoodLogById>(TYPES.GetFoodLogById)
  .toService(TYPES.AddFoodLog);

Personally I am now using abstract base classes as service identifiers so that I don鈥檛 have to provide the generic type parameters in order for type checking to work properly.
So the type parameters might need to be adjusted.

Have you tried using container.bind.toConstantValue?

Was this page helpful?
0 / 5 - 0 ratings