2017-02-16 18 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); 
    }; 
}; 

Примечание: указанные выше изменения будут работать на свойства экземпляра, но не статические свойства. Если вам нужно обрабатывать оба типа свойств, вам нужно будет добавить дополнительную логику, чтобы определить, следует ли использовать target или target.constructor

+0

О, фантастично. Ваш ответ - именно то, что мне нужно. Спасибо! Но предположим, я хотел пойти в другом направлении и поставить метаданные на прототипе вместо конструктора? Могу ли я пойти в другом направлении? – bkinsey808

+0

Несомненно, просто сделайте target.prototype – dtabuenc