I would like to pass an argument to a TypeScript decorator at runtime so that the decorated method will use that argument, the original method doesn't reqiure this to function but the decorator does.
I tried to achieve that by passing an argument to the decorated method and then find it within the decorator in the original method's arguments.
For example what I tried:
// calling a decorated method (nestJS code)
@Get('')
@UseGuards(JwtAuthGuard)
async getAll(@CurrentUser() user: User): Promise<any[]> {
//current user is a nestJS decorator extracts the user from the http header
const res = await this.whateverService.original(user);
return res;
}
// @MyDecorator usage
@MyDecorator()
async original(@user user: User): Promise<any>{
// return get all whatever
}
// @MyDecorator decorator
export function MyDecorator() {
return function (target: Object, propertyName: string | symbol, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
// get user param index
const userParamIndex = Reflect.getOwnMetadata(
userMetadataKey,
target,
propertyName
);
if (userParamIndex === undefined) {
throw new Error(`user undefined or missing @user decorator in method ${propertyName.toString()}`);
}
// override method descriptor with proxy method
descriptor.value = async function (...args: any[]) {
return new Promise(async (resolve, reject) => {
const user = args[userParamIndex];
let res;
try {
// await stuff using user arg;
res = await originalMethod();
} catch (err) {
reject(err);
} finally {
// await stuff;
resolve(res);
}
});
};
};
}
// @user decorator
export function user(
target: Object,
propertyKey: string | symbol,
parameterIndex: number
): void {
Reflect.defineMetadata(
userMetadataKey,
parameterIndex,
target,
propertyKey
);
}
The issue I have with this implementation is that the user argument in original is marked as declared but its value is never read. in the IDE.
Is there a way to let the IDE know that it is in use in the decorator? Or maybe a better implementation for that?
Edit
For some more context, the code I've added is simplified and doesn't includes all functionality. The purpose of all that is:
- get a single connection to a postgres db from a connection pool.
- setting the current_user_id to a session run time variable, for row level security needs.
- execute the original method that will execute db queries.
- reset the session run time variables.
- release the connection
- return the result of the original method.
Tech stack: NestJS & TypeORM. I'm trying to mimic something like TypeORM's Transaction decorator but with extra functionality.