2017-02-16 64 views
5

在打字稿中,是否可以使用属性装饰器为该类设置元数据?考虑下面的代码。类装饰器的“目标”显然与属性装饰器的“目标”不同。我可以从另一个派生出一个吗?可以打字稿属性装饰者设置类的元数据?

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

注输出:

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

我怎样才能获得元数据键也显示从属性装饰钥匙?

回答

3

是的,你可以随意在装饰器中做任何你想做的事情,但正如你发现的那样,你的问题与你传递的目标是一致的。

基本上,在属性装饰,所述target参数可以是取决于装饰是否对一个静态属性或实例属性时使用的两件事情之一:

在静态属性,所述target属性将是类构造函数。这意味着在静态属性上,目标将与您的类装饰器完全相同。

但是,在实例属性中,参数target将是您创建的类的prototype,而不是构造函数。这就是为什么你看到你所看到的行为。在实例属性的情况下,您的元数据不会像您的类装饰器一样附加到constructor

尽管如此,仍然有希望,因为您可以轻松地在给定原型实例的情况下访问构造函数,因为它存储在名为constructor的属性中。所以你的情况,你可以得到你做这个寻找的行为:

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

注:上述变化将工作实例属性,而不是静态属性。如果你需要处理这两种类型的属性,你需要添加一些额外的逻辑来决定是否使用targettarget.constructor

+0

哦,太棒了。你的回答正是我所需要的。非常感谢!但是,假设我想要朝另一个方向前进,并将元数据放在原型而不是构造函数上?我可以走向另一个方向吗? – bkinsey808

+0

当然,只要做target.prototype – dtabuenc