implements typed identifiers

This commit is contained in:
Robin Chappatte
2024-06-12 18:13:15 +02:00
parent b654a3b26f
commit c60af59bec
4 changed files with 112 additions and 155 deletions

View File

@@ -6,7 +6,9 @@ This lib provides a simplistic dependency manager.
- Resolves dependencies only when they are needed
- Detects circular dependency
- Allows "module" registration (grouped dependencies)
- Strong type support
The [previous major release](https://git.chpt.dev/Chappatte/Typescript-Dependency-Manager/src/tag/v1.1.1) used to allow asynchronous dependencies and the use of class as identifier, but those features were replaced by the `Symbol` identifier to keep the lib dead simple.
## Basic usage
@@ -16,66 +18,51 @@ import { DependencyManager } from 'dependency-manager/mod.ts'
// 1. Create a manager:
const manager = new DependencyManager();
// 2. Create a dependency:
const dependency = () => 'value';
// 2. Create a dependency (a provider and an identifier):
const value = 'foo';
const provider = () => value;
const identifier = Symbol() as DependencyIdentifier<typeof value>;
// 3. Register the dependency:
manager.register(dependency);
manager.register(identifier, provider);
// 4. Anywhere in your code, get the resolved dependency value:
const value = await manager.resolve(dependency);
// 4. Anywhere in your code, inject the resolved dependency value:
const value = await manager.inject(identifier);
```
## Identifier
An identifier is a uniq value used by the dependency manager to store and retrieve the dependency.
The `DependencyIdentifier` type allow the return value of the `inject` method to be fully typed,
## Providers
To register a dependency, we pass a function to the dependency manager.
This function is called a provider.
A dependency is rarely just a simple value like in the basic usage code and often rely on other dependencies.
Providers are called when resolving the dependency for the first time.
They receive the dependency manager as parameter, and should return the dependency value.
That's why the `register` method takes a function (that we call the dependency `provider`) who's role is to build the dependency.
Example of the registration of a dependency which provider uses another dependency:
That function receive a uniq parameter: The dependency manager.
That way it is possible to inject dependencies inside it:
```typescript
function dependency(manager: DependencyManager) {
const value = manager.resolve(otherDependency);
return `The value is: ${valueA}`;
function providerA() {
return 'foo'
}
manager.register(dependency);
manager.register(otherDependency);
```
const identifierA = Symbol() as DependencyIdentifier<ReturnType<typeof providerA>>;
## Typing
function providerB(manager: DependencyManager) {
const a = manager.inject(identifierA);
return `The value is: ${a}`;
}
const identifierB = Symbol() as DependencyIdentifier<ReturnType<typeof providerB>>;
The reason we pass the provider to resolve a dependency is that it allow the `resolve` method to correctly type the returned value:
manager.register(identifierA, providerA);
manager.register(identifierB, providerB);
```typescript
const A = () => 'foo';
const B = () => 42;
const C = () => ({});
// ...
const a = manager.resolve(A); //< `a` is of type `string`
const b = manager.resolve(B); //< `b` is of type `number`
const c = manager.resolve(C); //< `c` is of type `object`
```
## Modules
It is possible to register many dependency at once by using "modules".
A module is an object whose values are dependencies or modules.
```typescript
const moduleA = {
dependencyB: () => 'b',
moduleC: {
dependencyD: () => 'd',
},
};
manager.register(moduleA);
const d = manager.resolve(moduleA.moduleC.dependencyD);
const b = manager.inject(identifierB); // "The value is: foo"
```
## Errors
@@ -83,6 +70,6 @@ const d = manager.resolve(moduleA.moduleC.dependencyD);
The `register` method throw an error if:
- the dependency is already registred.
The `resolve` method throw an error if:
The `inject` method throw an error if:
- the dependency is not registred.
- a circular dependency is detected