Search code examples
javascripttypescriptnestjsdecoratorextends

Extend NestJS decorator


I stumbled across this question but I don't think I want to use an alias

I want to extend the express anyFilesInterceptor so I can work with a custom file object. I am not sure how to extend a decorator in NestJS.

So as a work around I tried decorator composition from another question. However, I am getting an error just trying to create a very basic (example in documentation) decorator

import { applyDecorators, createParamDecorator, ExecutionContext } from "@nestjs/common";
import { AnyFilesInterceptor } from "@nestjs/platform-express";

export function Test() {
  return applyDecorators(
    AnyFilesInterceptor,
    TestDecorator
  )
}

export const TestDecorator = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;

    return data ? user?.[data] : user;
  },
);

Now I can see from other discussions and the function naming that AnyFilesInterceptor is a mixin that returns a class while TestDecorator created by createParamDecorator likely only works on parameters.

Does NestJS have a way to create a class decorator? Or to extend existing decorators?


Solution

  • actually the AnyFilesInterceptor is a function itself that produces an interceptor (which is any class that implements NestInterceptor).
    You can see it by the usage: while 'other' interceptors may be used by simply giving the class to the UseInterceptor() decorator, this interceptor needs invocation (without new keyword).
    Example:

    @UseInterceptor(RegularInterceptor)
    //or
    @UseInterceptor(new RegularInterceptor())
    
    // AnyFilesInterceptor is a function returning a class
    @UseInterceptor(AnyFilesInterceptor())
    //or
    @UseInterceptor(new (AnyFilesInterceptor())({/* some multer options here */))
    

    so basically if you want to extend the AnyFilesInterceptor you simply need to define a class inteceptor of your own:

    export class MyAllFilesInterceptor extends AnyFilesInterceptor() {
      // YOU MUST OVERRIDE THE `intercept` METHOD!
      // also, give options to the `AnyFilesInterceptor` method if you wish
    }