Nougat Predominant Middleware

    @typeix/di
    TypeScript icon, indicating that this package has built-in type declarations

    8.1.1 • Public • Published

    Typeix Logo

    A progressive Node.js tools for building efficient and scalable applications.

    @typeix/di

    Build Status Coverage Status npm

    Dependency Injection

    Dependency Injection (DI) is a design pattern used to implement IoC. It allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them.

    Installing

    npm i @typeix/di --save

    Decorators

    Decorator Info
    @Injectable() specifies that Typeix can use this class in the DI system.
    decorators can be used on classes only.
    @Inject() specifies DI system, which object to provide when object is created,
    if there is no provider defined DI will throw error with explanation.
    @AfterConstruct() specifies DI system, what to execute immediately after object is created.
    @CreateProvider() decorator specifies DI system, to create new provider on injection point,
    this will create new object even if there is a provider defined in parent Injector.

    Interceptors

    An interceptor pattern is a software design pattern that is used when software systems or frameworks want to offer a way to change, or augment, their usual processing cycle.

    import {Injectable, Injector, Inject, createMethodInterceptor} from "@typeix/di";
    
    @Injectable()
    class LoggerInterceptor implements Interceptor {
    
      @Inject() logger: Logger;
    
      async invoke(method: Method): Promise<any> {
        const result = await method.invoke();
        this.logger.info(method.args.message, result);
        return result;
      }
    }
    
    export function Logger(message) {
      return createMethodInterceptor(Logger, LoggerInterceptor, {message});
    };
    
    @Injectable()
    class ChildService {
      @Logger("Logging ChildService.getName result: ")
      getName(): string {
        return this.name;
      }
    }

    Usage

    In order to create an object of some class you need to define class as @Injectable and injection points via @Inject, then when creating an instance you need to provide DI what to construct and which providers to create.

    import {Injectable, Injector, Inject} from "@typeix/di";
    
    @Injectable()
    class NameService {
    
      @Inject("name") private name: string;
    
      getName() {
        return this.name;
      }
    }
    
    @Injectable()
    class ChildService {
    
      @Inject() nameService: NameService;
    
      getName(): string {
        return this.nameService.getName();
      }
    }
    
    Injector.createAndResolve(ChildService, [
      {provide: "name", useValue: "Igor"},
      NameService
    ]).then(injector => {
      let service = injector.get(ChildService);
      return service.getName();
    });

    Provider Types

    There are three type of providers class, value and factory provider, functions inside providers array are converted to class providers.

    There are three types of providers in total:
    {provde, useClass} is a class provider.
    {provde, useFactory} is a factory provider.
    {provde, useValue} is a value provider.

    Dependent providers?: Array<Function | IProvider> inside of provider (class and factory) are extra dependencies that are created before provider and delivered as dependencies to provider itself.

    interface IProvider {
      provide: any;
      useValue?: any;
      useClass?: Function;
      useFactory?: Function;
      providers?: Array<Function | IProvider>;
    }

    Injector API

    NOTE:
    By default all providers are immutable, however you can define mutable provider keys.
    If provider is not mutable, and you are trying to create new instance of same provider on current Injector instance, injector will throw error.

    Injector.getProviders(provider: IProvider, propertyKey?: string) will return all providers which needs to be injected, if propertyKey is not defined injector will return providers for constructor.

    Injector.getAllMetadataForTarget(provider: IProvider) will return all metadata, injector cache them internally. Works with class provider only.

    class Injector {
      constructor(_parent?: Injector, keys?: Array<any>);
      static getProviders(provider: IProvider, propertyKey?: string): Array<IProvider>;
      // returns all metadata for provider
      static getAllMetadataForTarget(provider: IProvider): Array<IMetadata>;
      // creates new child injector, provider and providers
      static createAndResolveChild(parent: Injector, Class: Function | IProvider, providers: Array<MixedProvider>): Promise<Injector>;
      // creates new injector, provider and providers
      static createAndResolve(Class: Function | IProvider, providers: Array<MixedProvider>): Promise<Injector>;
      // creates new provider and providers
      createAndResolve(provider: IProvider, providers: Array<IProvider>): Promise<any>;
      // clens current injectables and all child injectors & providers
      destroy(): void;
      // check if providier exists on current SyncInjector instance
      has(key: any): boolean;
      // get provider value from current SyncInjector if not found bubble parrent's
      // if not found on any of parents exception is thrown.
      get(provider: string, Class?: IProvider): any;
      get<T>(provider: Type<T>, Class?: IProvider): T;
      // set provider and value
      set(key: any, value: Object): void;
      getParent(): Injector;
      setParent(injector: Injector): void;
      setName(provider: IProvider): void;
      hasChild(injector: Injector): boolean;
      addChild(injector: Injector): this;
    }

    Sync Injector API

    Since version 8.x default Injector behavior is converted to async API, if you want to use sync api you need to use Injector.Sync.createAndResolve or Injector.Sync.createAndResolveChild difference is that Async API supports Async providers, it's allowed to use of async/await in factory and return Promises in value provider!

    class SyncInjector {
      constructor(_parent?: Injector, keys?: Array<any>);
      static getProviders(provider: IProvider, propertyKey?: string): Array<IProvider>;
      // returns all metadata for provider
      static getAllMetadataForTarget(provider: IProvider): Array<IMetadata>;
      // creates new child injector, provider and providers
      static createAndResolveChild(parent: Injector, Class: Function | IProvider, providers: Array<MixedProvider>): Injector;
      // creates new injector, provider and providers
      static createAndResolve(Class: Function | IProvider, providers: Array<MixedProvider>): Injector;
      // creates new provider and providers
      createAndResolve(provider: IProvider, providers: Array<IProvider>): any;
      // clens current injectables and all child injectors & providers
      destroy(): void;
      // check if providier exists on current SyncInjector instance
      has(key: any): boolean;
      // get provider value from current SyncInjector if not found bubble parrent's
      // if not found on any of parents exception is thrown.
      get(provider: string, Class?: IProvider): any;
      get<T>(provider: Type<T>, Class?: IProvider): T;
      // set provider and value
      set(key: any, value: Object): void;
      getParent(): Injector;
      setParent(injector: Injector): void;
      setName(provider: IProvider): void;
      hasChild(injector: Injector): boolean;
      addChild(injector: Injector): this;
    }

    Install

    npm i @typeix/di

    Homepage

    typeix.com

    DownloadsWeekly Downloads

    89

    Version

    8.1.1

    License

    MIT

    Unpacked Size

    184 kB

    Total Files

    45

    Last publish

    Collaborators

    • avatar