From 13e167aa04f6a498a845105fde79ed6d43908314 Mon Sep 17 00:00:00 2001 From: wladimirgrf Date: Mon, 24 Jan 2022 16:10:30 -0300 Subject: [PATCH 1/4] [feat]: unregister methods to remove a single or all instances --- src/dependency-container.ts | 12 ++++++++++++ src/registry-base.ts | 4 ++++ src/types/dependency-container.ts | 3 +++ 3 files changed, 19 insertions(+) diff --git a/src/dependency-container.ts b/src/dependency-container.ts index ed29e54..cc981d0 100644 --- a/src/dependency-container.ts +++ b/src/dependency-container.ts @@ -374,6 +374,18 @@ class InternalDependencyContainer implements DependencyContainer { this.interceptors.postResolution.clear(); } + public unregisterAll(): void { + this._registry.clear(); + this.interceptors.preResolution.clear(); + this.interceptors.postResolution.clear(); + } + + public unregister(token: InjectionToken): void { + this._registry.delete(token); + this.interceptors.preResolution.delete(token); + this.interceptors.postResolution.delete(token); + } + public clearInstances(): void { for (const [token, registrations] of this._registry.entries()) { this._registry.setAll( diff --git a/src/registry-base.ts b/src/registry-base.ts index df3a406..a7be566 100644 --- a/src/registry-base.ts +++ b/src/registry-base.ts @@ -36,6 +36,10 @@ export default abstract class RegistryBase { this._registryMap.clear(); } + public delete(key: InjectionToken): void { + this._registryMap.delete(key); + } + private ensure(key: InjectionToken): void { if (!this._registryMap.has(key)) { this._registryMap.set(key, []); diff --git a/src/types/dependency-container.ts b/src/types/dependency-container.ts index c9d6653..47ed6b1 100644 --- a/src/types/dependency-container.ts +++ b/src/types/dependency-container.ts @@ -94,6 +94,9 @@ export default interface DependencyContainer { */ reset(): void; + unregisterAll(): void; + unregister(token: InjectionToken): void; + clearInstances(): void; createChildContainer(): DependencyContainer; From e68dc00bcbae703dfefe3c9244a1ab5abd9781fd Mon Sep 17 00:00:00 2001 From: wladimirgrf Date: Tue, 25 Jan 2022 09:01:59 -0300 Subject: [PATCH 2/4] [feat]: unregister tests --- src/__tests__/global-container.test.ts | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/__tests__/global-container.test.ts b/src/__tests__/global-container.test.ts index bda0ff2..b2353dc 100644 --- a/src/__tests__/global-container.test.ts +++ b/src/__tests__/global-container.test.ts @@ -370,6 +370,43 @@ test("clears cached instances from container.resolve() calls", () => { expect(instance3).toBeInstanceOf(Foo); }); +// --- unregister() --- + +test("unregister all instances", () => { + class Foo {} + const instance1 = new Foo(); + globalContainer.registerInstance("Test", instance1); + + expect(globalContainer.resolve("Test")).toBeInstanceOf(Foo); + + globalContainer.unregisterAll(); + + expect(() => { + globalContainer.resolve("Test"); + }).toThrow(); +}); + +test("unregister a single instance", () => { + class Foo {} + + const instance1 = new Foo(); + const instance2 = new Foo(); + + globalContainer.registerInstance("Test1", instance1); + globalContainer.registerInstance("Test2", instance2); + + expect(globalContainer.resolve("Test1")).toBeInstanceOf(Foo); + expect(globalContainer.resolve("Test2")).toBeInstanceOf(Foo); + + globalContainer.unregister("Test1"); + + expect(globalContainer.resolve("Test2")).toBeInstanceOf(Foo); + + expect(() => { + globalContainer.resolve("Test1"); + }).toThrow(); +}); + // --- @injectable --- test("@injectable resolves when not using DI", () => { From af2509de9e5d2159adcc5cd49c83f120cd89ce92 Mon Sep 17 00:00:00 2001 From: wladimirgrf Date: Tue, 25 Jan 2022 13:06:36 -0300 Subject: [PATCH 3/4] [fix]: unregister for non existing dependency --- src/__tests__/global-container.test.ts | 6 ++++++ src/dependency-container.ts | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/__tests__/global-container.test.ts b/src/__tests__/global-container.test.ts index b2353dc..0832961 100644 --- a/src/__tests__/global-container.test.ts +++ b/src/__tests__/global-container.test.ts @@ -407,6 +407,12 @@ test("unregister a single instance", () => { }).toThrow(); }); +test("fails to delete unregistered dependency by name", () => { + expect(() => { + globalContainer.unregister("NotRegistered"); + }).toThrow(); +}); + // --- @injectable --- test("@injectable resolves when not using DI", () => { diff --git a/src/dependency-container.ts b/src/dependency-container.ts index cc981d0..950f2a9 100644 --- a/src/dependency-container.ts +++ b/src/dependency-container.ts @@ -381,6 +381,14 @@ class InternalDependencyContainer implements DependencyContainer { } public unregister(token: InjectionToken): void { + const registration = this.getRegistration(token); + + if (!registration) { + throw new Error( + `Attempted to delete unregistered dependency token: "${token.toString()}"` + ); + } + this._registry.delete(token); this.interceptors.preResolution.delete(token); this.interceptors.postResolution.delete(token); From 4a005f3a1ab5e40d11d105613fd54c073a5f40ab Mon Sep 17 00:00:00 2001 From: wladimirgrf Date: Mon, 19 Sep 2022 20:45:55 -0300 Subject: [PATCH 4/4] [chore]: update readme with unregister --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 1fd96d0..ac54b3b 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ constructor injection. - [Interception](#interception) - [Child Containers](#child-containers) - [Clearing Instances](#clearing-instances) + - [Unregister](#unregister) - [Circular dependencies](#circular-dependencies) - [The `delay` helper function](#the-delay-helper-function) - [Interfaces and circular dependencies](#interfaces-and-circular-dependencies) @@ -595,6 +596,29 @@ test("something", () => { }); ``` +Unlike with `container.reset()`, the registrations themselves are not cleared. + +### Unregister +Unregister allows you to clear a previously created and registered instance. + +```typescript +class Foo {} +class Bar {} + +const myFoo = new Foo(); +container.registerInstance("MY_FOO", myFoo); + +const myBar = new Bar(); +container.registerInstance("MY_BAR", myBar); + +container.unregister("MY_BAR"); + +const myFoo2 = container.resolve("MY_FOO"); // resolved instance +const myBar2 = container.resolve("MY_BAR"); // throws error +``` + +Unlike `container.reset()`, unregister allows the removal of a specific token without affecting the others. + # Circular dependencies Sometimes you need to inject services that have cyclic dependencies between them. As an example: