Rename DIContainer to TSInjex and refactor interfaces

- Renamed DIContainer class and related references to TSInjex to better indicate its purpose as a TypeScript-based dependency injection container.
- Extracted IDependency interface to a separate file to improve modularity.
- Split the ITSInjex interface into ITSInjexRegister and ITSInjexResolve, then extended them in a new ITSInjex interface to clarify the separation of concerns.
- Updated tests and decorators to reflect the renaming and interface changes.
- Adjusted helper, functions, and index export to align with the new TSInjex structure.
This commit is contained in:
2024-08-14 20:21:05 +02:00
committed by Max P.
parent 8d607c7f0c
commit 3dbbfc8e1e
13 changed files with 106 additions and 59 deletions

View File

@@ -1,27 +1,13 @@
import { ImplementsStatic } from './helper/ImplementsStatic';
import { ITSInjex, ITSInjex_ } from './interfaces/IDIContainer';
import { IDependency } from './interfaces/IDependency';
import { ITSInjex, ITSInjex_ } from './interfaces/ITSInjex';
/**
* Dependency Entry Interface
*/
interface IDependency {
/**
* The dependency itself
*/
dependency: unknown;
/**
* If true, the dependency is deprecated => a warning
* is logged when the dependency is resolved
*/
deprecated?: boolean;
}
/**
* Dependency Injection Container
* **TSInjex**: Dependency Injection Container
*/
@ImplementsStatic<ITSInjex_>()
export class DIContainer implements ITSInjex {
private static _instance: DIContainer;
export class TSInjex implements ITSInjex {
private static _instance: TSInjex;
private readonly _dependencies = new Map<string, IDependency>();
/**
@@ -37,22 +23,47 @@ export class DIContainer implements ITSInjex {
*/
public static getInstance(): ITSInjex {
if (this._instance == null) {
this._instance = new DIContainer();
this._instance = new TSInjex();
}
return this._instance;
}
/**
* @inheritdoc
* @see {@link ITSInjexRegister.register}
*/
public static register<T>(
identifier: string,
dependency: T,
deprecated = false,
): void {
(TSInjex.getInstance() as TSInjex)._dependencies.set(identifier, {
dependency: dependency,
deprecated: deprecated,
});
}
/**
* @inheritdoc
* @see {@link ITSInjexResolve.resolve}
*/
public static resolve<T>(
identifier: string,
necessary = true,
): T | undefined {
return (TSInjex.getInstance() as TSInjex).resolve<T>(
identifier,
necessary,
);
}
//#endregion
//#region IDIContainer
/**
* Register a dependency
* @param identifier The identifier of the dependency
* @param dependency The dependency to register
* @param deprecated If true, the dependency is deprecated => a warning
* is logged when the dependency is resolved
* @inheritdoc
*/
public register<T>(
identifier: string,
@@ -66,11 +77,7 @@ export class DIContainer implements ITSInjex {
}
/**
* Resolve a dependency
* @param identifier The identifier of the dependency
* @param necessary If true, throws an error if the dependency is not found
* @returns The resolved dependency or undefined if the dependency is not found (if necessary is false)
* @throws Error if the dependency is not found (if necessary is true)
* @inheritdoc
*/
public resolve<T>(identifier: string, necessary = true): T | undefined {
const dependency = this._dependencies.get(identifier);

View File

@@ -1,4 +1,4 @@
import { test_IDIContainer } from './IDIContainer.spec';
import { DIContainer } from '../DIContainer';
import { TSInjex } from '../TSInjex';
test_IDIContainer(DIContainer);
test_IDIContainer(TSInjex);

View File

@@ -1,4 +1,4 @@
import { ITSInjex_, ITSInjex } from '../interfaces/IDIContainer';
import { ITSInjex_, ITSInjex } from '../interfaces/ITSInjex';
/**
* Test the implementation of a DIContainer
@@ -24,10 +24,21 @@ export function test_IDIContainer(Container: ITSInjex_): void {
expect(resolvedDependency).toBe(dependency);
});
it('should throw an error when resolving a non-registered dependency', () => {
it('should register and resolve a dependency static', () => {
const identifier = 'myDependency';
const dependency = { value: 42 };
Container.register(identifier, dependency);
const resolvedDependency =
Container.resolve<typeof dependency>(identifier);
expect(resolvedDependency).toBe(dependency);
});
it('should throw an error when resolving a non-registered dependency static', () => {
const identifier = 'nonExistentDependency';
expect(() => container.resolve<unknown>(identifier)).toThrow();
expect(() => Container.resolve<unknown>(identifier)).toThrow();
});
// Add more tests as necessary

View File

@@ -1,4 +1,4 @@
import { DIContainer } from '../DIContainer';
import { TSInjex } from '../TSInjex';
import { InitDelegate } from '../types/InitDelegate';
/**
@@ -12,7 +12,7 @@ import { InitDelegate } from '../types/InitDelegate';
* - If `true`, an error will be thrown if the dependency cannot be resolved.
* - If `false`, `undefined` will be returned if the dependency cannot be resolved.
* @returns A decorator function to be applied on the class property.
* @see {@link DIContainer}
* @see {@link TSInjex}
* @example
* ```ts
* class MyClass {
@@ -37,7 +37,7 @@ export function Inject<T, U>(
// Unique symbol to store the private property
const privatePropertyKey: unique symbol = Symbol();
// Get the DI container instance
const diContainer = DIContainer.getInstance();
const diContainer = TSInjex.getInstance();
// Function to evaluate the dependency lazily
// to avoid circular dependencies, not found dependencies, etc.

View File

@@ -1,4 +1,4 @@
import { DIContainer } from '../DIContainer';
import { TSInjex } from '../TSInjex';
/**
* A decorator to register a class in the DI (Dependency Injection) container.
@@ -20,7 +20,7 @@ export function Register<
>(identifier: string, deprecated?: boolean) {
return function (constructor: TargetType, ...args: unknown[]): void {
// Get the instance of the DI container
const diContainer = DIContainer.getInstance();
const diContainer = TSInjex.getInstance();
// Register the class in the DI container
diContainer.register(identifier, constructor, deprecated);

View File

@@ -1,4 +1,4 @@
import { DIContainer } from '../DIContainer';
import { TSInjex } from '../TSInjex';
import { InitDelegate } from '../types/InitDelegate';
/**
@@ -28,7 +28,7 @@ export function RegisterInstance<
) {
return function (constructor: TargetType, ...args: unknown[]): void {
// Get the instance of the DI container
const diContainer = DIContainer.getInstance();
const diContainer = TSInjex.getInstance();
// Create a proxy to instantiate the class when needed (Lazy Initialization)
let lazyProxy: unknown = new Proxy(

View File

@@ -1,11 +1,11 @@
import { DIContainer } from 'src/DIContainer';
import { TSInjex } from 'src/TSInjex';
/**
* Register a dependency.
* @param identifier The identifier of the dependency.
* @param dependency The dependency to register.
*/
export function Register<T>(identifier: string, dependency: T): void;
export function register<T>(identifier: string, dependency: T): void;
/**
* Register a dependency.
@@ -13,7 +13,7 @@ export function Register<T>(identifier: string, dependency: T): void;
* @param dependency The dependency to register.
* @param deprecated A warning is logged when the dependency is resolved.
*/
export function Register<T>(
export function register<T>(
identifier: string,
dependency: T,
deprecated?: true,
@@ -26,10 +26,10 @@ export function Register<T>(
* @param deprecated If true, the dependency is deprecated => a warning
* is logged when the dependency is resolved.
*/
export function Register<T>(
export function register<T>(
identifier: string,
dependency: T,
deprecated?: boolean,
): void {
DIContainer.getInstance().register(identifier, dependency, deprecated);
TSInjex.getInstance().register(identifier, dependency, deprecated);
}

View File

@@ -1,5 +1,5 @@
import { DIContainer } from '../DIContainer';
import { DependencyResolutionError } from '../interfaces/Exceptions';
import { TSInjex } from '../TSInjex';
/**
* Resolve a dependency.
@@ -7,7 +7,7 @@ import { DependencyResolutionError } from '../interfaces/Exceptions';
* @returns The resolved dependency.
* @throws A {@link DependencyResolutionError} if the dependency is not found.
*/
export function Resolve<T>(identifier: string): T;
export function resolve<T>(identifier: string): T;
/**
* Resolve a dependency
@@ -15,7 +15,7 @@ export function Resolve<T>(identifier: string): T;
* @param necessary The dependency is **not** necessary.
* @returns The resolved dependency or undefined if the dependency is not found.
*/
export function Resolve<T>(identifier: string, necessary: false): T | undefined;
export function resolve<T>(identifier: string, necessary: false): T | undefined;
/**
* Resolve a dependency.
@@ -25,9 +25,9 @@ export function Resolve<T>(identifier: string, necessary: false): T | undefined;
* 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.
*/
export function Resolve<T>(
export function resolve<T>(
identifier: string,
necessary?: boolean,
): T | undefined {
return DIContainer.getInstance().resolve<T>(identifier, necessary);
return TSInjex.getInstance().resolve<T>(identifier, necessary);
}

View File

@@ -0,0 +1,5 @@
export * from './TSInjex';
export * from './decorators/Inject';
export * from './decorators/Register';
export * from './decorators/RegisterInstance';

View File

@@ -1,4 +1,4 @@
import { ITSInjex } from './IDIContainer';
import { ITSInjex } from './ITSInjex';
/**
* General error class for {@link ITSInjex} interface.

View File

@@ -0,0 +1,14 @@
/**
* Dependency Entry Interface
*/
export interface IDependency {
/**
* The dependency itself
*/
dependency: unknown;
/**
* If true, the dependency is deprecated => a warning
* is logged when the dependency is resolved
*/
deprecated?: boolean;
}

View File

@@ -1,17 +1,17 @@
/**
* Static Dependency Injection Container Interface
* Static TSInjex Interface
*/
export interface ITSInjex_ {
export interface ITSInjex_ extends ITSInjexRegister, ITSInjexResolve {
/**
* Get the **singleton** Dependency Injection Container
* Get the **singleton** TSInjex instance.
*/
getInstance(): ITSInjex;
}
/**
* Dependency Injection Container Interface
* Register method for static and instance Dependency Injection Container.
*/
export interface ITSInjex {
export interface ITSInjexRegister {
/**
* Register a dependency.
* @param identifier The identifier of the dependency.
@@ -34,7 +34,12 @@ export interface ITSInjex {
* @param deprecated No warning is logged when the dependency is resolved.
*/
register<T>(identifier: string, dependency: T, deprecated?: false): void;
}
/**
* Resolve method for static and instance Dependency Injection Container.
*/
export interface ITSInjexResolve {
/**
* Resolve a dependency
* @param identifier The identifier of the dependency
@@ -58,3 +63,8 @@ export interface ITSInjex {
*/
resolve<T>(identifier: string, necessary?: false): T | undefined;
}
/**
* TSInjex Interface
*/
export interface ITSInjex extends ITSInjexRegister, ITSInjexResolve {}