Skip to content

Instantly share code, notes, and snippets.

@josephdpurcell
Created September 7, 2022 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephdpurcell/fc04cfd428a6ee9d7ffb64685e4fe3a6 to your computer and use it in GitHub Desktop.
Save josephdpurcell/fc04cfd428a6ee9d7ffb64685e4fe3a6 to your computer and use it in GitHub Desktop.
Get ArgumentMetadata in NestJS createParamDecorator
import { ArgumentMetadata, createParamDecorator, ExecutionContext } from '@nestjs/common';
import { METADATA__PARAM_TYPE } from '../constants'; // METADATA__PARAM_TYPE = 'myType'
import { paramTypeEnhancer } from './param-type.enhancer';
export const MyDecorator = createParamDecorator(
async (data: unknown, ctx: ExecutionContext): Promise<any> => {
const metatype = Reflect.getOwnMetadata(METADATA__PARAM_TYPE, ctx.getHandler());
// We build the argument metadata that @nestjs/class-validator is expecting.
// Specifically, we specify the type as "custom" -- this is a special value
// coming from NestJS and all custom decorators are "custom". The data is
// left undefined (only a @Query or @Param type would have data). Last, the
// metatype is the reference to the type.
const argument: ArgumentMetadata = {
type: 'custom',
data: undefined,
metatype: metatype,
};
// Do processing here. You can even return a promise.
// Often you want access to the request which can be done like this:
const request = ctx.switchToHttp().getRequest();
},
[paramTypeEnhancer],
);
import { ParamDecoratorEnhancer } from '@nestjs/common';
import { METADATA__PARAM_TYPE } from '../constants'; // METADATA__PARAM_TYPE = 'myType'
/**
* This enhancer grabs the Typescript type of the parameter and shoves it into
* the metadata. We do this because the CustomParamFactory does not have access
* to the type of param.
*/
export const paramTypeEnhancer: ParamDecoratorEnhancer = (
target: Record<string, unknown>,
propertyKey: string,
parameterIndex: number,
): void => {
// Typescript adds the "design:paramtypes" metadata with an array of class
// types where the keys are the method argument index and the value is the
// class type.
const paramTypes = Reflect.getOwnMetadata('design:paramtypes', target, propertyKey);
// We can use the parameterIndex to retrieve the specific type we want.
const metatype = paramTypes[parameterIndex];
// Now, we assign the parameter type to the metadata at a key we know.
Reflect.defineMetadata(METADATA__PARAM_TYPE, metatype, target[propertyKey]);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment