All files / decorators RegisterInstance.ts

100% Statements 18/18
100% Branches 6/6
100% Functions 4/4
100% Lines 18/18

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  1x                                       1x                 4x   4x       4x       4x 2x 1x   1x     4x     4x     2x 2x 1x   1x     2x     2x             4x      
import { Identifier } from 'src/types/Identifier';
import { TSinjex } from '../classes/TSinjex';
import { InitDelegate } from '../types/InitDelegate';
 
/**
 * A decorator to register an instance of a class in the DI (Dependency Injection) container.
 * @template TargetType The type of the class whose instance is to be registered.
 * @param identifier The identifier used to register the instance in the DI container.
 * @see {@link Identifier} for more information on identifiers.
 * @param init An optional initializer function which get the constructor of the class
 * as input and returns an instance of the class.
 * @see {@link InitDelegate} for more information on initializer functions.
 * @returns The decorator function to be applied on the class.
 * @example
 * ```ts
 * \@RegisterInstance('MyClassInstanceIdentifier', (constructor) => new constructor())
 * class MyClass {
 *   // ...
 * }
 * ```
 */
export function RegisterInstance<
    TargetType extends new (..._args: unknown[]) => InstanceType<TargetType>,
>(
    identifier: Identifier,
    init?: InitDelegate<
        TargetType & { new (..._args: unknown[]): InstanceType<TargetType> },
        InstanceType<TargetType>
    >,
) {
    return function (constructor: TargetType, ...args: unknown[]): void {
        // Get the instance of the DI container
        const diContainer = TSinjex.getInstance();
        let instance: InstanceType<TargetType>;
 
        // Create a proxy to instantiate the class when needed (Lazy Initialization)
        let lazyProxy: unknown = new Proxy(
            {},
            {
                get(target, prop, receiver) {
                    if (instance == null) {
                        if (init) {
                            instance = init(constructor);
                        } else {
                            instance = new constructor(...args);
                        }
                    }
                    lazyProxy = instance;
 
                    // Return the requested property of the instance
                    return instance[prop as keyof InstanceType<TargetType>];
                },
                set(target, prop, value, receiver) {
                    if (instance == null) {
                        if (init) {
                            instance = init(constructor);
                        } else {
                            instance = new constructor(...args);
                        }
                    }
                    lazyProxy = instance;
 
                    // Set the requested property of the instance
                    return (instance[prop as keyof InstanceType<TargetType>] =
                        value);
                },
            },
        );
 
        // Register the lazy proxy in the DI container
        diContainer.register(identifier, lazyProxy);
    };
}
 
Zur TypeDoc-Dokumentation