diff --git a/src/__tests__/disposable.test.ts b/src/__tests__/disposable.test.ts index efa838f..29007d5 100644 --- a/src/__tests__/disposable.test.ts +++ b/src/__tests__/disposable.test.ts @@ -10,6 +10,7 @@ describe("Disposable", () => { it("returns false when dispose method takes too many args", () => { const specialDisposable = { + // eslint-disable-next-line @typescript-eslint/no-unused-vars dispose(_: any) {} }; diff --git a/src/__tests__/global-container.test.ts b/src/__tests__/global-container.test.ts index 5685d03..b261117 100644 --- a/src/__tests__/global-container.test.ts +++ b/src/__tests__/global-container.test.ts @@ -861,13 +861,29 @@ describe("dispose", () => { it("disposes all child disposables", () => { const container = globalContainer.createChildContainer(); + container.registerInstance(Bar, new Bar()); + container.register("ValueBar", {useValue: new Bar()}); + container.register("FactoryBar", { + useFactory: () => new Bar() + }); + container.register("ClassBar", Bar); + container.register("TokenBar", {useToken: "ValueBar"}); + const foo = container.resolve(Foo); const bar = container.resolve(Bar); + const valueBar = container.resolve("ValueBar"); + const factoryBar = container.resolve("FactoryBar"); + const classBar = container.resolve("ClassBar"); + const tokenBar = container.resolve("TokenBar"); container.dispose(); expect(foo.disposed).toBeTruthy(); - expect(bar.disposed).toBeTruthy(); + expect(bar.dispose).toBeTruthy(); + expect(valueBar.disposed).toBeTruthy(); + expect(factoryBar.disposed).toBeTruthy(); + expect(classBar.disposed).toBeTruthy(); + expect(tokenBar.disposed).toBeTruthy(); }); it("disposes asynchronous disposables", async () => { @@ -894,14 +910,17 @@ describe("dispose", () => { expect(foo2.disposed).toBeTruthy(); }); - it("doesn't dispose of instances created external to the container", () => { - const foo = new Foo(); + it("disposes all instances that were resolved together", () => { const container = globalContainer.createChildContainer(); - container.registerInstance(Foo, foo); - container.resolve(Foo); + container.register("FooList", {useValue: new Foo()}); + container.register("FooList", {useValue: new Bar()}); + + const fooList = container.resolveAll("FooList"); + container.dispose(); - expect(foo.disposed).toBeFalsy(); + expect(fooList[0].disposed).toBeTruthy(); + expect(fooList[1].disposed).toBeTruthy(); }); }); diff --git a/src/dependency-container.ts b/src/dependency-container.ts index fb74644..95f7c5c 100644 --- a/src/dependency-container.ts +++ b/src/dependency-container.ts @@ -311,11 +311,13 @@ class InternalDependencyContainer implements DependencyContainer { const returnInstance = isSingleton || isContainerScoped; + let newResolution = true; let resolved: T; if (isValueProvider(registration.provider)) { resolved = registration.provider.useValue; } else if (isTokenProvider(registration.provider)) { + newResolution = returnInstance; resolved = returnInstance ? registration.instance || (registration.instance = this.resolve( @@ -324,6 +326,7 @@ class InternalDependencyContainer implements DependencyContainer { )) : this.resolve(registration.provider.useToken, context); } else if (isClassProvider(registration.provider)) { + newResolution = returnInstance; resolved = returnInstance ? registration.instance || (registration.instance = this.construct( @@ -334,6 +337,7 @@ class InternalDependencyContainer implements DependencyContainer { } else if (isFactoryProvider(registration.provider)) { resolved = registration.provider.useFactory(this); } else { + newResolution = false; resolved = this.construct(registration.provider, context); } @@ -342,6 +346,11 @@ class InternalDependencyContainer implements DependencyContainer { context.scopedResolutions.set(registration, resolved); } + // If this is a new resolution and the instance is disposable, add it to our set of disposables + if (newResolution && isDisposable(resolved)) { + this.disposables.add(resolved); + } + return resolved; } diff --git a/src/types/disposable.ts b/src/types/disposable.ts index 9ffcebe..e416d09 100644 --- a/src/types/disposable.ts +++ b/src/types/disposable.ts @@ -3,7 +3,9 @@ export default interface Disposable { } export function isDisposable(value: any): value is Disposable { - if (typeof value.dispose !== "function") return false; + if (typeof value !== "object" || typeof value.dispose !== "function") { + return false; + } const disposeFun: Function = value.dispose;