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

Posted

技术标签:

【中文标题】如何创建简单的 Typescript 元数据注释【英文标题】:How to Create a Simple Typescript Metadata Annotation 【发布时间】:2016-10-31 08:26:51 【问题描述】:

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

所以,我想使用自定义序列化器序列化我的 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
       
    ));

任何与此相近的东西都是可以接受的,欢迎任何帮助。 谢谢

【问题讨论】:

【参考方案1】:

我下面的解决方案建立在:

    TypeScript Decorators Metadata spec (early stage/experimental)

先决条件:

    在您的 tsconfig.json 或命令行中启用 TypeScript 中的装饰器和装饰器元数据支持:

tsconfig.json


    "compilerOptions": 
        "target": "es5", // you have to target es5+
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
        // ....
    
    // ...

    安装reflect-metadata

    npm install --save-dev reflect-metadata

serializerWith装饰者(厂)

装饰器工厂是接受一个或多个参数并返回 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);

示例

ma​​in.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

【讨论】:

以上是关于如何创建简单的 Typescript 元数据注释的主要内容,如果未能解决你的问题,请参考以下文章

如何注释采用可变长度元组的函数? (可变元组类型注释)

具有复制属性的类方法的元数据在更改源类的元数据时发生更改 - Typescript

TypeScript 按任意类型过滤元组类型

如何在 TypeScript 3+ 中正确键入通用元组剩余参数?

TypeScript系列教程15TypeScript 元组

通过 typescript 3.0 通用休息元组类型从类元组返回实例元组