Angular Property Decorator создает только один экземпляр свойства для каждого типа класса
Я использую Property Decorator для создания Observable со статическим getter/setter для каждого свойства.
В конце концов, вы можете использовать декоратор таким образом
class Test {
@ObservableProperty(DEFAULT_CATS)
cats: number;
@ObservableProperty(DEFAULT_PIGS)
pigs: number;
}
Фактический код для декоратора
export function ObservableProperty(defaultValue = null): any {
return (target, key, descriptor) => {
const accessor = `${key}$`;
target[accessor] = new BehaviorSubject(defaultValue);
return Object.assign({}, descriptor, {
get: function() {
return this[accessor].getValue();
},
set: function(value: any) {
this[accessor].next(value);
},
});
};
}
Теперь все работает нормально с одним экземпляром Test
составная часть.
Но в двух случаях этот тест на самом деле не проходит.
fdescribe('ObservableProperty Decorator', () => {
let test: Test;
let doppleganger: Test;
beforeEach(() => {
test = new Test();
doppleganger = new Test();
});
it('should create different observables for each props', () => {
expect(test['cats$'] === doppleganger['cats$']).toBe(false);
});
})
Поскольку декоратор работает с прототипом экземпляров компонентов, созданные переменные точно такие же.
Как я могу обойти эту проблему?
Если это не может быть сделано с декоратором, что элегантный альтернативный способ?
1 ответ
Я собираюсь ответить на вопрос с решением, которое я нашел после одного дня размышлений.
Прежде всего, главная проблема, для которой я не мог получить доступ к экземпляру, заключалась в использовании функции стрелки в определении декоратора. Итак, я изменился:
return (target, key, descriptor) => {
в
return function (target, key) {
Таким образом, я мог получить доступ к экземпляру из getter/setter, используя this
,
Затем мне нужно было найти хорошее место для инициализации BehaviourSubject. Делать это в getter или setter основного свойства не получится (я хочу получить доступ this.cats$
без доступа в первую очередь this.cats
).
Так что я решил с новым геттером для cats$
, Это хранит переменную в секретном свойстве и создает ее, если она не существует.
Вот окончательный код!
export function ObservableProperty(defaultValue = null): any {
return function (target, key) {
const accessor = `${key}$`;
const secret = `_${key}$`;
Object.defineProperty(target, accessor, {
get: function () {
if (this[secret]) {
return this[secret];
}
this[secret] = new BehaviorSubject(defaultValue);
return this[secret];
},
set: function() {
throw new Error('You cannot set this property in the Component if you use @ObservableProperty');
},
});
Object.defineProperty(target, key, {
get: function () {
return this[accessor].getValue();
},
set: function (value: any) {
this[accessor].next(value);
},
});
};
}