如何创建简单的 Typescript 元数据注释

How to Create a Simple Typescript Metadata Annotation

我有一些字段需要在发送到服务器端之前进行格式化。

所以,我想使用自定义序列化器序列化我的打字稿 类 的某些字段,这样的事情是理想的:

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
       }
    }));
}

任何接近于此的内容都是可以接受的,欢迎提供任何帮助。 谢谢

我的以下解决方案基于:

  1. TypeScript Decorators
  2. Metadata spec (early stage/experimental)

先决条件:

  1. 在您的 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装饰师(工厂)

装饰器工厂是一种带有一个或多个参数的东西,returns TypeScript 在生成的 JavaScript 代码中使用的装饰器函数。

我选择直接将序列化函数传递到我的装饰器工厂,并使用元数据规范的 reflect-metadata 实现将序列化函数与 属性 相关联。我稍后会检索它并在 运行 时使用它。

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";
}

然后我们可以像这样应用装饰器工厂:

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