Ответ 1
Мое решение ниже построено поверх:
Требования:
- Включить поддержку метаданных Decorator и decorator в TypeScript в
tsconfig.json
или в командной строке:
tsconfig.json
{
"compilerOptions": {
"target": "es5", // you have to target es5+
"experimentalDecorators": true,
"emitDecoratorMetadata": true
// ....
}
// ...
}
-
Установить
reflect-metadata
пакетnpm install --save-dev
reflect-metadata
serializerWith
Декоратор (factory)
Декоратор factory - это то, что принимает один или несколько параметров и возвращает функцию декоратора, которую TypeScript использует в сгенерированном JavaScript-коде.
Я решил напрямую передать функцию сериализации в мой декоратор factory и использовать реализацию reflect-metadata
спецификации metdata, чтобы связать функцию serializer с свойством. Я позже извлечу его и использую его во время выполнения.
function serializeWith(serializer: (input: any) => string) : (target: any, propertyKey: string) => void {
return function(target: any, propertyKey: string) {
// serialization here is the metadata key (something like a category)
Reflect.defineMetadata("serialization", serializer, target, propertyKey);
}
}
Использование
Учитывая этот сериализатор:
function MyDateSerializer(value : any) : string {
console.log("MyDateSerializer called");
return "dummy value";
}
Затем мы можем применить декоратор factory следующим образом:
import "reflect-metadata"; // has to be imported before any decorator which uses it is applied
class Greeter {
@serializeWith(MyDateSerializer)
public greeting : string;
constructor(message: string) {
this.greeting = message;
}
}
И мы можем использовать и использовать сериализатор следующим образом:
var greetingInstance = new Greeter("hi");
var serializerFunc : (input: any) => string = Reflect.getMetadata("serialization", greetingInstance, "greeting");
serializerFunc(greetingInstance.greeting);
Пример
main.ts
import "reflect-metadata";
function serializeWith(serializer: (input: any) => string) : (target: any, propertyKey: string) => void {
return function(target: any, propertyKey: string) {
console.log("serializeWith called: adding metadata");
Reflect.defineMetadata("serialization", serializer, target, propertyKey);
}
}
function MyDateSerializer(value : any) : string {
console.log("MyDateSerializer called");
return "bla";
}
class Greeter {
@serializeWith(MyDateSerializer)
public greeting : string;
constructor(message: string) {
console.log("Greeter constructor");
this.greeting = message;
}
}
var greetingInstance = new Greeter("hi");
var serializerFunc : (input: any) => string = Reflect.getMetadata("serialization", greetingInstance, "greeting");
var serializedValue = serializerFunc(greetingInstance.greeting);
console.log(serializedValue);
Результаты
c:\code\tmp\lll>node build\main.js
serializeWith called: adding metadata
Greeter constructor
MyDateSerializer called
bla