How to pass an argument to a TypeScript decorator at runtime?

Viewed 614

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:

  1. get a single connection to a postgres db from a connection pool.
  2. setting the current_user_id to a session run time variable, for row level security needs.
  3. execute the original method that will execute db queries.
  4. reset the session run time variables.
  5. release the connection
  6. 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.

0 Answers
Related