typescriptdecoratortypescript-decorator

Can I access method parameters in a method decorator declaration in Typescript?


I have a method decorator that accepts a string key as an argument. It is being applied to a method, and I would like to access the method's parameters inside of the decorator declaration in order to use the method parameter(s) as the key. Is it possible to do something like this?

Note: I am using RxJS in this example to be able to cache the result after the network call

function CacheData(mapKey: string) {
   return function(target: any, propertyKey: string, descriptor: PropertyDescription) {
        descriptor.value = function(...args: any[]) {
            if (sessionStorage.getItem(mapKey)) {
                // return cached result
                return of(sessionStorage.getItem(mapKey));
            } else {
                // return original network request call and cache result
                return descriptor.value.apply(this, args).pipe(
                    tap(result => sessionStorage.setItem(mapKey, result));
                );
            }
        }
        return descriptor;
    } 
}

@CacheData(`key-${param1}`)
function getDetails(param1: string, param2: any): GetDetailsResponse {
    return http.get(`https://swapi.dev/api/people/${param1}`).subscribe();
}

Solution

  • Create a new function inside the decorator and assign it to descriptor.value

    This gives you control over its arguments. E.g.:

    function CacheData(keyFn: (...keyArgs: any[]) => string) {
      return function (
        target: any,
        propertyKey: string,
        descriptor: PropertyDescriptor
      ) {
        const originalMethod = descriptor.value;
    
        descriptor.value = function (...args: any[]) { // these are your args!
          const key = keyFn(...args);
    
          if (cache.hasOwnProperty(key)) {
            return cache[key]; // return cached result
          }
    
          const result = originalMethod.apply(this, args);
          cache[key] = result;
          return result;
        };
    
        return descriptor;
      };
    }
    

    You can apply the function like this:

    @CacheData((param1: string, param2: number) => `key-${param1}-${param2}`)
    function getDetails(param1: string, param2: any): GetDetailsResponse {
        // implementation
    }
    

    in this case passing

    (param1: string, param2: number) => `key-${param1}-${param2}`
    

    as keyFn.