[Fixed] Passing variables to injected services to use as decorator argument


I have an Angular project that uses services that very often repeat themselves with the typical create/read/update/delete/read-list-of-all-entries. I also very often want to manipulate received data in similar ways after receiving it. So I wrote decorators that use apply which "transform" the data in a way determined by the parameter passed to them (the parameter is always an object class).

In normal use this looks like this:

  providedIn: 'root'
export class RuleService {

  rulesUrl: string = `${Constants.wikiApiUrl}/rule/`;

  constructor(private http: HttpClient) {}

  getRule(pk: number): Observable<Rule>{
    return this.http.get<Rule>(`${this.rulesUrl}/${pk}`);

This happens a lot, so I want to write a parent-service that I can extend:


  providedIn: 'root'
export abstract class GenericObjectService{
  baseUrl: string;

    private http: HttpClient,
    public objectClass: any,
  ) {}

  @TransformObservable(this.objectClass) //This line won't work
  read(pk: number): Observable<any>{
    return this.http.get(`${this.baseUrl}/${pk}`);

The issue is that I can’t use "this" for a decorator parameter, it doesn’t exist at the time of parsing IIRC. But is there a way I could pass the decorator-parameter to my injected service somehow so that it may be used by the decorator?

Find below also the "TransformObservable" decorator:

export function TransformObservable(modelClass: any){
    /**Decorator to apply transformObservableContent */
    return function(target: any, propertyKey: string, descriptor: PropertyDescriptor){

        const originalMethod = descriptor.value;
        descriptor.value = function(){
            const observable = originalMethod.apply(this, arguments);
            return transformObservableContent(observable, modelClass);
        return descriptor;


The this keyword will not be available outside of function scopes. However, you may define the needed object as a field/property in same class and in the decorator annotation, you may just pass a string that decorator function will lookup, or pass in an actual object reference.

In the decorator, check the argument that was passed to the annotation:

if(typeof modelClass === 'string'){
  // lookup a property in decorated class definition
  modelClass = target[modelClass]; // or, this[modelClass]
}else {
  // assume modelClass is the needed object

This will allow you to use:

// or

Distinction between target and this:

The target passed to decorator function is the object that defines the class where the decorator is used. It will have all the properties and methods defined in the class and can be used to retrieve them as shown above. However target is not the runtime this you would generally use inside the class methods. Its only the replacement method (descriptor.value) that will have this available inside it, like original method.

Hence, if you really need this and not just the decorated class definition, you must move all the code inside the replacement function descriptor.value. There you have access to this as well as all the parameters that are passed to the decorator and the decorator factory.

Leave a Reply

(*) Required, Your email will not be published