Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 2x 2x 1x 1x 2x 2x | import { Identifier } from 'src/types/Identifier';
import { TSinjex } from '../classes/TSinjex';
import { InitDelegate } from '../types/InitDelegate';
/**
* A decorator to inject a dependency from a DI (Dependency Injection) container into a class property.
* @template T The type of the dependency to be injected.
* @template U The type of the property to be injected.
* @param identifier The identifier used to resolve the class in the DI container.
* @see {@link Identifier} for more information on identifiers.
* @param init An optional initializer function to transform the dependency before injection.
* @see {@link InitDelegate} for more information on initializer functions.
* @param necessary If true, throws an error if the dependency is not found.
* @returns The resolved dependency or undefined if the dependency is not necessary
* and not found, or throws an error if the dependency is necessary and not found.
* @throws A {@link DependencyResolutionError} if the dependency is not found and necessary.
* @example
* ```ts
* class MyClass {
* \@Inject<MyDependency>('MyDependencyIdentifier')
* private myDependency!: MyDependency;
* }
* ```
* @example
* ```ts
* class MyClass {
* \@Inject('ILogger_', (x: ILogger_) => x.getLogger('Tags'), false)
* private _logger?: ILogger;
* }
* ```
*/
export function Inject<T, U>(
identifier: Identifier,
init?: InitDelegate<T, U>,
necessary = true,
) {
return function (target: unknown, propertyKey: string | symbol): void {
// Unique symbol to store the private property
const privatePropertyKey: unique symbol = Symbol();
// Get the DI container instance
const diContainer = TSinjex.getInstance();
// Function to evaluate the dependency lazily
// to avoid circular dependencies, not found dependencies, etc.
const evaluate = (): T | undefined => {
return diContainer.resolve<T>(identifier, necessary);
};
// Define the property
Object.defineProperty(target, propertyKey, {
get() {
// If the property is not defined, evaluate the dependency
if (!this.hasOwnProperty(privatePropertyKey)) {
if (init) {
try {
this[privatePropertyKey] = init(evaluate() as T);
} catch (error) {
if (necessary) {
throw error;
}
}
} else {
this[privatePropertyKey] = evaluate();
}
}
return this[privatePropertyKey];
},
// Not necessary to set the property
// set(value: PropertieType) {
// this[privatePropertyKey] = value;
// },
enumerable: true,
configurable: false,
});
};
}
|