Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access class metadata from method decorator

I'm having two decorators. A class decorator and a method decorator. The class decorator defines metadata which I want to access in the method decorator.

ClassDecorator:

function ClassDecorator(topic?: string): ClassDecorator {
    return (target) => {
        Reflect.defineMetadata('topic', topic, target);
        // I've also tried target.prototype instead of target
        return target;
    };
}

MethodDecorator:

interface methodDecoratorOptions {
    cmd: string
}

function MethodDecorator(options: decoratorOptions) {
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        // HERE IS MY PROBLEM
        console.log('metaData is: ', Reflect.getMetadata('topic', target));
    }
}

And this is my Class definition:

@ClassDecorator('auth')
export class LoginClass {

    @MethodDecorator({
        cmd: 'login'
    })
    myMethod() {
        console.log('METHOD CALLED');
    }
}

THE PROBLEM:

The following line of the MethodDecorator returns metaData is: undefined. Why is it undefined?

console.log('metaData is: ', Reflect.getMetadata('topic', target));

THE QUESTION:

How can I access the metadata defined by the ClassDecorator from the MethodDecorator?

like image 869
tmuecksch Avatar asked Jan 19 '18 13:01

tmuecksch


People also ask

Which decorator is used to identify a class?

Class Decorators The class decorator is applied to the constructor of the class and can be used to observe, modify, or replace a class definition.

How do decorators work in TypeScript?

Using Decorator Syntax In TypeScript, you can create decorators using the special syntax @expression , where expression is a function that will be called automatically during runtime with details about the target of the decorator. The target of a decorator depends on where you add them.

What is metadata in angular with example?

Metadata is used to decorate a class so that it can configure the expected behavior of the class. Following are the different parts for metadata. Annotations − These are decorators at the class level. This is an array and an example having both the @Component and @Routes decorator.

Which decorator is applicable for component class coded using TypeScript Mcq?

Class Decorators A class decorator is applied to the constructor of the class. A class decorator can be used to observe, modify, or replace a class definition. If the class decorator returns a value, it will replace the class declaration with the given constructor function.


1 Answers

The problem is the order in which decorators get executed. Method decorators are executed first, class decorators are executed after. This makes sense if you think about it, the class decorators need the complete class to act upon, and creating the class involves creating the methods and calling their decorators first.

A simple workaround would be for the method decorator to register a callback that would then be called by the class decorator after the topic was set:

function ClassDecorator(topic?: string): ClassDecorator {
    return (target) => {
        Reflect.defineMetadata('topic', topic, target.prototype);
        let topicFns: Array<() => void> = Reflect.getMetadata("topicCallbacks", target.prototype);
        if (topicFns) {
            topicFns.forEach(fn => fn());
        }
        return target;
    };
}

interface methodDecoratorOptions {
    cmd: string
}

function MethodDecorator(options: methodDecoratorOptions) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        let topicFns: Array<() => void> = Reflect.getMetadata("topicCallbacks", target);
        if (!topicFns) {
            Reflect.defineMetadata("topicCallbacks", topicFns = [], target);
        }
        topicFns.push(() => {
            console.log('metaData is: ', Reflect.getMetadata('topic', target));
        });
    }
}

@ClassDecorator('auth')
class LoginClass {

    @MethodDecorator({
        cmd: 'login'
    })
    myMethod() {
        console.log('METHOD CALLED');
    }
}
like image 89
Titian Cernicova-Dragomir Avatar answered Oct 12 '22 09:10

Titian Cernicova-Dragomir