angulartypescriptdecorator

Angular | Inject service into decorator


I am trying to inject a service into a decorator function in which I am creating, this is so I can get the contents that are stored inside of variables.

I currently have a basic decorator setup.

export function canEdit(editName: string, service: Service) {
      return function (constructor: any) {
          console.log(constructor);
      }
}

Where I am using this it is asking me for the second parameter, which obviously needs to be dependency injected.

I have also tried the @Inject(Service) which isn't allowed within functions.

Is there a way that I can do this?

Or is it possible to get the parent classes variables within the decorator?


Solution

  • Decorators are a TypeScript feature that work outside of Angular's dependency injection system.

    The only solution that I know of is to create a special service that will expose dependencies to the decorator.

    @Injectable()
    export class DecoratorService {
         private static service: Service | undefined = undefined;
         public constructor(service: Service) {
             DecoratorService.service = service;
         }
         public static getService(): Service {
             if(!DecoratorService.service) {
                 throw new Error('DecoratorService not initialized');
             }
             return DecoratorService.service;
         }
    }
    

    You can now access the injected service via the above class.

    export function canEdit(editName: string) {
          return function (constructor: any) {
              const service = DecoratorService.getService();
              // ^^^ access dependency here
              console.log(constructor);
          }
    }
    

    The above will not work unless something in the Angular application depends upon DecoratorService because Angular creates instances when they are needed. So you can inject it into a module to force it to be initialized.

    @NgModule({
        provides: [
            DecoratorService
        ]
    })
    export class MainModule {
        public constructor(service: DecoratorService) {
                          // ^^^ forces an instance to be created
        }
    }