Search code examples
node.jstypescriptnestjsdecorator

NestJs - Calling a method from a service inside a Custom Decorator


Based on this answer, I tried to implement a function from another service inside a decorator.

Here is my attempt:

export function ClearCache() {
  const injectCacheService = Inject(CacheService);

  return (target: any, _: string, propertyDescriptor: PropertyDescriptor) => {
    injectCacheService(target, 'service'); // this is the same as using constructor(private readonly logger: LoggerService) in a class

    //get original method
    const originalMethod = propertyDescriptor.value;

    //redefine descriptor value within own function block
    propertyDescriptor.value = async function (...args: any[]) {
      try {
        console.log(this);
        const service: CacheService = this.service;
        service.clearCacheById(args[1]);

        return await originalMethod.apply(this, args);
      } catch (error) {
        console.error(error);
      }
    };
  };
}

But I got Property 'service' does not exist on type 'PropertyDescriptor'.ts(2339)

Any idea on what part I am missing?

Update:

tsconfig.json has "strict":true. If it is enabled, then "this" would be strictly use the PropertyDescriptor interface.

Fixed the issue by changing "strict": false in the tsconfig.json.

How to reproduce?

  • Use "strict":true on tsconfig.json

Solution

  • Its unclear if you are using the NestJS cache-manager wrapper, if so you need to use the provider token when injecting and the type would be Cache.

    export function ClearCache() {
        
        const injector = Inject(CACHE_MANAGER)
    
        return (target: any, _key?: string | symbol, descriptor?: TypedPropertyDescriptor<any>) => {
            
            injector(target, 'cacheManager')
    
            const originalMethod = descriptor.value
    
            descriptor.value = async function (...args: any[]) {
                try {
                    const service: Cache = this.cacheManager
                    service.delete(args[1])
                    return await originalMethod.apply(this, args)
                } catch (err) {
                    console.error(err)
                    return originalMethod(args)
                }
            }
        }
    }
    

    If it is a different service, ensure that you are using the correct provider token, it is in the current modules scope and instantiated. If it isn't in current module, check it is global

    Uploaded minimal repo of above code here.

    Update:

    tsconfig.json has "strict":true. If it is enabled, then "this" would be strictly use the PropertyDescriptor interface.

    Fixed the issue by changing "strict": false in the tsconfig.json.