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: diff --git a/src/__tests__/global-container.test.ts b/src/__tests__/global-container.test.ts index 5685d03..2985440 100644 --- a/src/__tests__/global-container.test.ts +++ b/src/__tests__/global-container.test.ts @@ -371,6 +371,49 @@ 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(); +}); + +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 4158fa4..11b7794 100644 --- a/src/dependency-container.ts +++ b/src/dependency-container.ts @@ -394,6 +394,26 @@ 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 { + 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); + } + public clearInstances(): void { this.ensureNotDisposed(); 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 25aface..44d657d 100644 --- a/src/types/dependency-container.ts +++ b/src/types/dependency-container.ts @@ -95,6 +95,9 @@ export default interface DependencyContainer extends Disposable { */ reset(): void; + unregisterAll(): void; + unregister(token: InjectionToken): void; + clearInstances(): void; createChildContainer(): DependencyContainer;