Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modules and scopes support #2

Merged
merged 6 commits into from
Nov 10, 2024
Merged

Modules and scopes support #2

merged 6 commits into from
Nov 10, 2024

Conversation

Evyweb
Copy link
Owner

@Evyweb Evyweb commented Nov 10, 2024

Modules

You can also use modules to organize your dependencies.

Loading modules

Modules can then be loaded in your container.
By default, when you create a container, it is using a default module under the hood.

const module1 = createModule();
module1.bind(DI.DEP1).toValue('dependency1');

const module2 = createModule();
module2.bind(DI.DEP2).toValue(42);

const module3 = createModule();
module3.bind(DI.MY_SERVICE).toHigherOrderFunction(MyService, {dep1: DI.DEP1, dep2: DI.DEP2});

const container = createContainer();
container.load(Symbol('module1'), module1);
container.load(Symbol('module2'), module2);
container.load(Symbol('module3'), module3);

const myService = container.get<MyServiceInterface>(DI.MY_SERVICE);

The dependencies do not need to be registered in the same module as the one that is using them.
Note that the module name used as a key is a symbol.

Modules override

You can also override dependencies of a module. The dependencies of the module will be overridden by the dependencies of the last loaded module.

const module1 = createModule();
module1.bind(DI.DEP1).toValue('OLD dependency1');
module1.bind(DI.MY_SERVICE).toFunction(sayHelloWorld);

const module2 = createModule();
module2.bind(DI.DEP1).toValue('NEW dependency1');

const module3 = createModule();
module3.bind(DI.MY_SERVICE).toHigherOrderFunction(MyService, {dep1: DI.DEP1, dep2: DI.DEP2});

const container = createContainer();
container.bind(DI.DEP2).toValue(42); // Default module
container.load(Symbol('module1'), module1);
container.load(Symbol('module2'), module2);
container.load(Symbol('module3'), module3);

// The dependency DI.MY_SERVICE will be resolved with the higher order function and dep1 will be 'NEW dependency1'
const myService = container.get<MyServiceInterface>(DI.MY_SERVICE);

Unload modules

You can also unload a module from the container. The dependencies of the module will be removed from the container.
Already cached instances will be removed to keep consistency and avoid potential errors.

const module1 = createModule();
module1.bind(DI.DEP1).toValue('dependency1');

const container = createContainer();
container.load(Symbol('module1'), module1);

container.unload(Symbol('module1'));

// Will throw an error as the dependency is not registered anymore
const myService = container.get<string>(DI.DEP1); 

Using scopes

Singleton scope (default)

In singleton scope, the container returns the same instance every time a dependency is resolved.

container.bind(DI.MY_SERVICE).toClass(MyServiceClass, [DI.DEP1, DI.DEP2]);
// or
container.bind(DI.MY_SERVICE).toClass(MyServiceClass, [DI.DEP1, DI.DEP2], 'singleton');

const instance1 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);
const instance2 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);

console.log(instance1 === instance2); // true

Transient scope

In transient scope, the container returns a new instance every time the dependency is resolved.

container.bind(DI.MY_SERVICE).toClass(MyServiceClass, [DI.DEP1, DI.DEP2], 'transient');

const instance1 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);
const instance2 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);

console.log(instance1 === instance2); // false

Scoped Scope

In scoped scope, the container returns the same instance within a scope. Different scopes will have different instances.

To use the scoped scope, you need to create a scope using runInScope.

container.bind(DI.MY_SERVICE).toClass(MyServiceClass, [DI.DEP1, DI.DEP2], 'scoped');

container.runInScope(() => {
    const instance1 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);
    const instance2 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);

    console.log(instance1 === instance2); // true
});

container.runInScope(() => {
    const instance3 = container.get<MyServiceClassInterface>(DI.MY_SERVICE);

    console.log(instance3 === instance1); // false
});

Note: If you try to resolve a scoped dependency outside a scope, an error will be thrown.

@Evyweb Evyweb self-assigned this Nov 10, 2024
@Evyweb Evyweb merged commit 4957dfb into master Nov 10, 2024
1 check passed
@Evyweb Evyweb deleted the feature/modules-scopes branch November 10, 2024 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant