My approach detailed below is based on:
- TypeScript Decorators
- Metadata spec (early stage/experimental)
Requirements:
- Make sure to enable Decorator and decorator metadata support in TypeScript by updating your
tsconfig.json
or via the command line:
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
// Other configurations...
}
}
Install the reflect-metadata
package
npm install --save-dev reflect-metadata
serializerWith
Decorator (factory)
A decorator factory is a function that takes one or more parameters and returns another function, which TypeScript uses as a decorator in the compiled JavaScript code.
In my implementation, I pass the serialization function directly into the decorator factory and utilize the reflect-metadata
library to link the serializer with the property using the metadata spec. This allows me to retrieve and apply it at runtime.
function serializeWith(serializer: (input: any) => string): (target: any, propertyKey: string) => void {
return function(target: any, propertyKey: string) {
Reflect.defineMetadata("serialization", serializer, target, propertyKey);
}
}
Implementation Example
Considering this example of a serializer:
function MyDateSerializer(value: any): string {
console.log("MyDateSerializer called");
return "dummy value";
}
We can then implement the decorator factory as follows:
import "reflect-metadata";
class Greeter {
@serializeWith(MyDateSerializer)
public greeting: string;
constructor(message: string) {
this.greeting = message;
}
}
To access and use the serializer, you can do the following:
var greetingInstance = new Greeter("hi");
var serializerFunc: (input: any) => string = Reflect.getMetadata("serialization", greetingInstance, "greeting");
serializerFunc(greetingInstance.greeting);
Sample Code
main.ts
import "reflect-metadata";
// Implementation details
Outputs
c:\code\tmp\lll>node build\main.js
SerializeWith called: adding metadata
Greeter constructor
MyDateSerializer called
bla