microsoft / tsyringe

Lightweight dependency injection container for JavaScript/TypeScript
MIT License
5.18k stars 172 forks source link

Singleton created multiple times #158

Closed jekabs-karklins closed 3 years ago

jekabs-karklins commented 3 years ago

Describe the bug Class decorated with @singleton is created multiple times.

To Reproduce

// Foo.ts This is a singleton and must be created only once
import { singleton } from "tsyringe";

@singleton()
export class Foo {
  constructor() {
    console.log("Constructor of Foo");
  }
}
// Bar.ts this is Bar and must be created every time. It uses the singleton
import { inject, injectable, Lifecycle, scoped } from "tsyringe";
import { Foo } from "./Foo";

@injectable()
export class Bar {
  constructor(@inject("Foo") private foo: Foo) {
    console.log("Constructor of Bar");
  }
}
// main.ts this is resolving Bar two times.
import "reflect-metadata";
import { container } from "tsyringe";
import { Bar } from "./Bar";
import { Foo } from "./Foo";

container.register("Foo", { useClass: Foo });
container.register("Bar", { useClass: Bar });

const instance = container.resolve(Bar);
const instance1 = container.resolve(Bar);

Expected behavior Console output

Constructor of Foo
Constructor of Bar
Constructor of Bar

Actual behavior Console output

Constructor of Foo
Constructor of Bar
Constructor of Foo
Constructor of Bar

Version: 4.4.0

MeltingMosaic commented 3 years ago

You shouldn't use both @singleton and @injectable at the same time - I suspect that might be the cause of your issue.

jekabs-karklins commented 3 years ago

You shouldn't use both @singleton and @injectable at the same time - I suspect that might be the cause of your issue.

Hi, I have updated the example. The result is still the same

MeltingMosaic commented 3 years ago

Ah, I think I have it - @singleton registers the type in the global container using the type as the injection token. Your call to container.register("Foo", { useClass: Foo }); registers the type using the string "Foo" as the token. So a couple of possibilities here

jekabs-karklins commented 3 years ago

Thank you, that was it. Registering Foo like this solves the issue

container.register(
  "Foo",
  { useClass: Foo },
  { lifecycle: Lifecycle.Singleton }
);