简体   繁体   English

可以使用typescript属性装饰器为类设置元数据吗?

[英]can typescript property decorators set metadata for the class?

In typescript, is it possible to use a property decorator to set metadata for the class? 在typescript中,是否可以使用属性装饰器为类设置元数据? Consider the code below. 请考虑以下代码。 The "target" of the class decorator is apparently not the same as the "target" of the property decorator. 类装饰器的“目标”显然与属性装饰器的“目标”不同。 Can I derive one from the other? 我可以从另一个中获得一个吗?

import 'reflect-metadata';


const MY_CLASS_DECORATOR_KEY = 'MyClassDecoratorKey';
const MY_PROPERTY_DECORATOR_KEY = 'MyPropertyDecoratorKey';

export const MyClassDecorator = options => {
    return function (target) {
      console.log('class target: ' , target);
      Reflect.defineMetadata(MY_CLASS_DECORATOR_KEY, options, target);
    };
};

export const MyPropertyDecorator = (options): PropertyDecorator => {
    return (target, property) => {
      console.log('property target: ' , target);
      const metadata = Reflect.getMetadata(MY_PROPERTY_DECORATOR_KEY, target) || {};
      metadata[property] = options;
      Reflect.defineMetadata(MY_PROPERTY_DECORATOR_KEY, metadata, target);
    };
};

@MyClassDecorator('my class decorator value')
class MyClass {
    @MyPropertyDecorator('first my property decorator value')
    myFirstProperty: any;

    @MyPropertyDecorator('second my property decorator value')
    mySecondProperty: any;
}

console.log('keys: ', Reflect.getMetadataKeys(MyClass));

Note the output: 注意输出:

property target:  MyClass {}
property target:  MyClass {}
class target:  function MyClass() {
    }
keys:  [ 'MyClassDecoratorKey' ]

How can I get the metadata keys to also show keys from the property decorator? 如何获取元数据键以显示属性装饰器中的键?

Yes you are free to do whatever you want in your decorator, but as you found out, your issues is with the target you are being passed. 是的,你可以自由地在你的装饰工作中做任何你想做的事情,但是当你发现时,你的问题就在于你正在通过的目标。

Basically, in a property decorator, the target parameter can be one of two things depending on whether the decorator is used on a static property or an instance property: 基本上,在属性装饰器中, target参数可以是两件事之一,具体取决于装饰器是用于静态属性还是实例属性:

On a static property, the target property will be the class constructor function . 在静态属性上, target属性将是类构造函数 This means that on a static property the target will be exactly the same as it is for your class decorator. 这意味着在静态属性上,目标将与类装饰器完全相同。

However, on an instance property, the target parameter will be the prototype of the class you created, not the constructor. 但是,在实例属性上, target参数将是您创建的类的prototype ,而不是构造函数。 This is why you are seeing the behavior you are seeing. 这就是你看到你所看到的行为的原因。 In the case of an instance property your metadata is not being attached to the constructor as is the case with your class decorator. 对于实例属性,您的元数据未附加到constructor就像类装饰器一样。

There is still hope though, because you can easily get to the constructor function given a prototype instance as it is stored in a property called constructor . 但仍然有希望,因为你可以很容易地获得给定一个原型实例的构造函数,因为它存储在一个名为constructor的属性中。 So in your case, you can get the behavior you are looking for by doing this: 因此,在您的情况下,您可以通过执行以下操作获得您正在寻找的行为:

export const MyPropertyDecorator = (options): PropertyDecorator => {
    return (target, property) => {
      var classConstructor = target.constructor;
      console.log('property target: ' , classConstructor);
      const metadata = Reflect.getMetadata(MY_PROPERTY_DECORATOR_KEY, classConstructor) || {};
      metadata[property] = options;
      Reflect.defineMetadata(MY_PROPERTY_DECORATOR_KEY, metadata, classConstructor);
    };
};

NOTE: the above change would work for instance properties, but not static properties. 注意:上述更改适用于实例属性,但不适用于静态属性。 If you need to handle both types of properties you would need to add some additional logic to determine whether to use target or target.constructor 如果需要处理这两种类型的属性,则需要添加一些额外的逻辑来确定是使用target还是target.constructor

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM