4

我正在使用反射元数据库和 Typescript 装饰器。

例如,我有这个类(真正的会有更多的字段):

class Message {
    @FieldTyping
    text: string;

    @FieldTyping
    code: number;

    constructor(text: string, code: number) {
        this.text = text;
        this.code = code;
    }
}

装饰器也很合成,但在实际代码中它最终会这样做:

function FieldTyping(target: Object, key: string) {
    Reflect.getMetadata('design:type', target, key)
    // "String" output in console for "text" key
}

现在它工作正常,但我想减少样板。所以我想使用一个装饰器并在构造函数中声明所有字段,例如:

@ClassTyping
class Message {
    constructor(public text: string, public code: number) { }
}

装饰器应该遍历所有公共字段并做同样的工作FieldTyping——从反射中获取实际类型。所以我想要两件事:

  1. 从类中获取所有密钥。(因为我只需要string名字)
  2. targetReflect.getMetadata. _

但是target在类装饰器中是一个构造函数,而不是Object. 我能够通过一些“hack”访问类密钥:

type ConstructorType<T> = {
    new (...args: any[]): T
}

function ClassTyping<T>(target: ConstructorType<T>) {
    const obj = new target()
    const fields = Object.keys(obj)

    fields.map(prop => Reflect.getMetadata('design:type', target, field))
    // "undefined" output for all fields
}

所以我用undefined值创建类实例并在不知道它的实际类型的情况下获取它的键(公共字段)。但我有问题target。我试图在这种情况下使用任何变体而不是实际target参数:

  • target.prototype为了从中获取Object构造函数;
  • obj作为 this 的一个新实例Object
  • 就像Message一种类型

但是它们都不起作用,在所有情况下我都得到了“未定义”类型。从我的实验来看,即使没有装饰器和简单的参数,似乎在任何其他地方Reflect.getMetadata也不起作用:

Reflect.getMetadata('design:type', Message, "text")

显然它只适用现场target装饰器,至少对我来说。我在这个主题中挖掘了整个 SO,但没有找到任何适合我特定目的的解决方案。

所以请告诉这是否可能或我错过了什么。

注意:

  1. 我知道使用正则表达式绝对有可能,但我不想要这种丑陋的解决方案。
  2. 它是客户端代码,因此我无法访问文件系统并解析源以获取ts-morph类型,例如(或者我又错过了一些东西)
  3. 确实"emitDecoratorMetadata": true_tsconfig.json
  4. 我的堆栈只是 NPM 和 Parcel 作为捆绑器。在本地环境中与 Parcel 开发服务器一起使用,在“生产”中与 Harp 一起使用(在 Heroku 上)。
4

0 回答 0