Overview
I’ve been developing a prototype for a library that offers some type annotations and does post processing of instances of annotated types, and I was suprised that, in spite of the ample blog posts/articles that describes TypeScript decorators, how hard is to find some simple examples that explains both the annotation and the detection part. So here you are!
Decorator examples
The examples use the reflect-metadata
library to make the
examples more concice, so don’t forget to import:
import "reflect-metadata"
and the following declaration is also used in all of the examples:
const markedKey = Symbol("marked")
Class decorators
Consider the class annotation marked_class
:
@marked_class
class A {
...
}
A simple decorator for the annotation:
function marked_class<T>(
constructor: T /* constructor of the class */
) {
Reflect.defineMetadata(markedKey, "marked with default value", constructor)
}
or if you also want to pass parameters:
@marked_class("my value")
class A {
...
}
a decorator factory can be developed:
function marked_class<T>(value: string){
return function (
constructor: T /* constructor of the class */
) {
Reflect.defineMetadata(markedKey, value, constructor)
}
}
And this is how to check if an object is instance of an annotated class:
function getClassMark(obj: any) {
return Reflect.getMetadata(markedKey, obj.constructor)
}
Method decorators
Consider the method annotation marked_method
:
class A {
@marked_method
doA(){...}
}
A simple decorator for the annotation:
function marked_method<T>(
target: T, /* prototype of the class or constructor function of the class for a static member */
propertyKey: string,
descriptor: PropertyDescriptor
) {
Reflect.defineMetadata(markedkey, "marked with default value", target, propertyKey)
}
if you also want to pass parameters:
class A {
@marked_method("my value")
doA(){...}
}
the decorator factory can be:
function marked_method<T>(value: string){
return function (
target: T, /* prototype of the class or constructor function of the class for a static member */
propertyKey: string,
descriptor: PropertyDescriptor
) {
Reflect.defineMetadata(markedkey, value, target, propertyKey)
}
}
And this is how to check if a method of an object is annotated:
function getMethodMark(obj: any, methodName: string) {
return Reflect.getMetadata(markedKey, obj, methodName)
}
Property decorators
Consider the property annotation marked_property
:
class A {
@marked_property
propertyA = ...
}
A simple decorator for the annotation:
function marked_method<T>(
target: T, /* prototype of the class or constructor function of the class for a static member */
propertyKey: string
) {
Reflect.defineMetadata(markedkey, "marked with default value", target, propertyKey)
}
descriptor: PropertyDescriptor
parameter compared to method annotationsif you also want to pass parameters:
class A {
@marked_property("my value")
propertyA = ...
}
the decorator factory can be:
function marked_method<T>(value: string){
return function (
target: T, /* prototype of the class or constructor function of the class for a static member */
propertyKey: string
) {
Reflect.defineMetadata(markedkey, value, target, propertyKey)
}
}
And this is how to check if a property of an object is annotated:
function getPropertyMark(obj: any, propertyName: string) {
return Reflect.getMetadata(markedKey, obj, propertyName)
}