Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if property is decorated with specific annotation - Typescript

How can I determine if a specific property is decorated with a specific annotation?

For example this class:

class A {
    @DecoratedWithThis
    thisProp: number;
}

How can I know that thisProp is decorated with DecoratedWithThis?

My use case: I use the class from another file to generate code and HTML for the properties.

Could you imagine of another solution?

like image 982
Philipp Fock Avatar asked Jul 04 '18 09:07

Philipp Fock


People also ask

What are the property decorators in TypeScript?

A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression , where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.

What is target in Decorator TypeScript?

target: Constructor function of the class if we used decorator on the static member, or prototype of the class if we used decorator on instance member. In our case it is firstMessage which is an instance member, so the target will refer to the prototype of the Greeter class. propertyKey: It is the name of the property.

How do you use TS decorators?

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.

Is Decorator a type variable in TypeScript?

A Decorator is a special kind of declaration that can be applied to classes, methods, accessor, property, or parameter.


1 Answers

There is no native way that I know of in typescript, but there is a way to do it using 'reflect-metadata' library https://github.com/rbuckton/reflect-metadata which is a proposed extension to native reflection api.

Decorators are just functions that get executed when your class is defined. in your case you want to create a property decorator

function (target, propertyKey) {}

Where target is your Object.prototype and name is the property name

Per Reflect Metadata Documentation

// define metadata on an object or property
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);

// get metadata value of a metadata key on the prototype chain of an object or property
let result = Reflect.getMetadata(metadataKey, target, propertyKey);

You can solve your problem by adding metadata to your property that you can read later on to check if that property has been decorated.

Example Implementation

import 'reflect-metadata';

const metadataKey = 'MyDecorator';

function MyDecorator(target, propertyKey) {
    Reflect.defineMetadata(metadataKey, true, target, propertyKey);
}

function myDecoratorUsingClass<T>(type:  Type<T>, propertyKey: string) {
    return myDecoratorUsingInstance(new type(), propertyKey);
}

function myDecoratorUsingInstance<T>(instance: T, propertyKey: string) {
  return !!Reflect.getMetadata(metadataKey, instance, propertyKey);
}

class MyClass {
   @MyDecorator
   property1;
   property2;
}

console.log(myDecoratorUsingClass(MyClass, 'property1')); // true
console.log(myDecoratorUsingClass(MyClass, 'property2')); // false

const instance = new MyClass();
console.log(myDecoratorUsingInstance(instance, 'property1')); // true
console.log(myDecoratorUsingInstance(instance, 'property2')); // false

NOTE To use myDecoratorUsingClass your class should have a constructor where all the parameters are optional (or no parameters)

like image 162
h0ss Avatar answered Sep 28 '22 11:09

h0ss