Фреймворк ember
активно использует декораторы. Теперь, чтобы использовать привязку данных, я должен украсить свои свойства @tracked
, что дает мне все мои приятные обновления пользовательского интерфейса каждый раз, когда я меняю свойство.
@tracked username = 'dave';
Это хорошо работает, но я сталкиваюсь с некоторыми серьезными проблемами, если мне нужно добавить собственный декоратор поверх отслеживаемого декоратора.
@typed(StateTrackMap)
@tracked
mapConfigsArray = [create(StateTrackMap)];
Я могу заставить это работать, с помощью проверки моего @typed
декоратора, чтобы увидеть, находится ли он выше другого декоратора или нет.
export default function typed(classType) {
let weak = new WeakMap();
return function(object, property, descriptor) {
return {
get() {
// Check if there is another decorator attached below us in the chain
// i.e. "tracked"
if (typeof descriptor.get == 'function') {
return descriptor.get.call(this);
}
// If we haven't initialized before but there is one ready, return that
if (!weak.has(this) && typeof descriptor.initializer == 'function') {
weak.set(this, descriptor.initializer.call(this));
}
return weak.get(this);
},
set(value) {
// my set code which does the type checking/converting this descriptor is for
// Apply the converted value to the lower level object
// This may be the object itself, or it may be another setter in the chain
if (typeof descriptor.set == 'function') {
descriptor.set.call(this, typedValue);
} else {
return weak.set(this, typedValue);
}
}
}
}
}
Но это кажется странным ... и не похоже ни на одно из использованных мной дескрипторов. Главным образом потому, что если я изменю порядок декораторов, то взорвется
@tracked
@typed(StateTrackMap)
mapConfigsArray = [create(StateTrackMap)];
index.js:172 Uncaught Error: Assertion Failed: The options object passed to tracked() may only contain a 'value' or 'initializer' property, not both.
Так что я думаю, мой вопрос в том, как правильно связать декораторы с get
& set
? Мне кажется, что порядок декораторов определяет, могу ли я go вверх / вниз по цепочке или нет. Также мне кажется, что логика цепочки c должна быть запечена в каждом декораторе, иначе она не работает. Есть ли какой-нибудь общий способ, которым я могу передать декораторы другим декораторам?
Я видел несколько примеров, в которых я возвращал ссылку на дескриптор, но это, похоже, не помогло решить проблему и здесь, так как я не совсем уверен, как я все еще могу вставить свой get/set
в него, не стирая цепочка собственности или попадание в ту же лодку, что и выше, где мой код должен быть разработан специально для работы с другими дескрипторами.
export default function typed(classType) {
return function(object, property, descriptor) {
const set = descriptor.set;
const get = descriptor.get;
const weak = new WeakMap();
descriptor.get = function() {
if (typeof get == 'function') {
return get.call(this);
}
// If we haven't initialized before but there is one ready, return that
if (!weak.has(this) && typeof descriptor.initializer == 'function') {
weak.set(this, descriptor.initializer.call(this));
}
return weak.get(this);
}
descriptor.set = function(value) {
// My type checking / conversion code
// Apply the converted value to the lower level object
// This may be the object itself, or it may be another setter in the chain
if (typeof set == 'function') {
set.call(this, typedValue);
} else {
return weak.set(this, typedValue);
}
}
return descriptor;
}
}
Кстати, этот метод вызывает другой взрыв.
Assertion Failed: You attempted to use @tracked on mapConfigsArray, but that element is not a class field.