Подтвердить что ты не робот

Как создать простую Typescript Аннотацию метаданных

У меня есть некоторые поля, которые нужно отформатировать перед отправкой на сервер.

Итак, я хотел бы сериализовать некоторые поля моих классов typescript, используя пользовательские сериализаторы, что-то вроде этого было бы идеальным:

export class Person {
    @serializeWith(MyDateSerializer)
    private date: Date;
}

post(url, value) {
    this.http.post(url, JSON.stringfy(value, (key, val) => {
       if (//value has serializeWith annotation) {
           return //serialize with custom serializer
       }
    }));
}

Все, что близко к этому, было бы приемлемым, любая помощь приветствуется. Благодаря

4b9b3361

Ответ 1

Мое решение ниже построено поверх:

Требования:

  • Включить поддержку метаданных Decorator и decorator в TypeScript в tsconfig.json или в командной строке:

tsconfig.json

{
    "compilerOptions": {
        "target": "es5", // you have to target es5+
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
        // ....
    }
    // ...
}
  1. Установить 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