emberjs glimmer object set() с переменным именем свойства
У меня есть компонент в Ember 3.15, где я пытаюсь сделать что-то вроде
import { action, set } from '@ember/object';
@action
someMethod() {
const value = ... // something random
let propertyName = ... // some variable string
set(this, propertyName, value);
}
Кажется, что в браузере все работает нормально, но машинописный текст помечает заданную строку как ошибку (в частности, аргумент propertyName). Итак, если это работает, почему машинописному тексту это не нравится?
Это также, похоже, происходит с get(), где ему не нравятся переменные propertyNames, такие как get(this, propertyName)
.
2 ответа
В описанной вами ситуации есть две основные проблемы: одна связана с TypeScript, а другая - нет.
Проблема TypeScript заключается в том, что TS знает имена свойств в целом и будет проверять правильность настройки - как при использовании обычного поиска и назначения свойств JS, так и при использовании Ember's get
а также set
функции. В частности, типы для Ember стараются убедиться, что вы не опечатаете что-то при выполненииget
а также set
. Вы можете понять, почему они не разрешают произвольные строки в этом примере:
import Component from '@ember/component';
import { action, set } from '@ember/object';
export default class Whoops extends Component {
greeting = 'Hello';
@action updateGreeting(newGreeting) {
set(this, 'greering', newGreeting);
// ----^--- TYPO!!!
}
}
Если типы для set
(или get
) просто разрешены произвольные строки, TS здесь ничем не поможет; он отпустит ее, и вам придется самостоятельно выяснять ошибку, вместо того, чтобы компилятор услужливо сообщал вам об этом заранее.
В случае, если вы столкнулись, TypeScript, вероятно, просто видит строку и говорит: "У меня нет способа проверить, принадлежит ли эта строка свойству".
Здесь есть несколько способов улучшить ситуацию. Прежде всего, если вы можете, вам следует выяснить, можно ли ограничить типpropertyName
быть keyof
для типа, из которого он исходит. (Объясняяkeyof
выходит за рамки этого ответа, этот раздел в руководстве и этот пост в блоге помогут вам быстрее.)
Во-вторых, это связано с более серьезной проблемой: вы отметили при обсуждении другого ответа на этот вопрос, что проблема в том, что вы пытаетесь глубоко установить свойства для одного фрагмента отслеживаемого корневого состояния. В общем, вы не должны таким образом изменять автоматически отслеживаемое состояние - это пережиток старых шаблонов, управляемых наблюдателями, которые Ember Classic использовал со своими вычисляемыми свойствами. Вместо этого лучше управлять всеми изменениями в этом автоматически отслеживаемом состоянии через владельца этого состояния. Тогда тебе не понадобитсяset
вообще, и система будет корректно обновляться автоматически.
Вы можете сделать это либо путем вложенного состояния сам по себе быть autotracked, либо путем определения класса для него или использовать что - то вроде отслеживаемых встроенных модулей, чтобы обернуть простой объект JS. В любом случае, вместо того, чтобы проникать в это состояние и глубоко изменять его откуда угодно, сделайте это только на объекте, которому принадлежит это состояние. Если вы последуете этому шаблону и ограничитеpropertyName
быть keyof TheOwnerOfTheState
где TheOwnerOfTheState
это какой-то класс, все будет "просто работать" - как со стороны Ember, так и со стороны TypeScript.
Как правило, если ваша собственность @tracked
тебе не нужно set
и может просто сделать this[propertyName] = value;
.
Однако ваша проблема, вероятно, связана с общим ограничением машинописного текста. Актуально общая проблема статической типизации:
Машинопись выполняет только статический анализ. Таким образом, он не выполняет ваш код. Таким образом, он не может знать, действительно ли существует динамически сгенерированный ключ свойства.
Итак, если у вас есть что-то вроде этого:
class Foo {
data1: number = 1;
data2: number = 2;
foo() {
const fixedProp = 'data1';
console.log(this[fixedProp]);
const dynamicProp = 'data' + (1 + 1);
console.log(this[dynamicProp]);
}
}
Тогда машинописный текст не сможет проверить, если this[dynamicProp]
на самом деле существует, потому что для этого необходимо выполнить 'data' + (1 + 1);
чтобы он знал, что dynamicProp
на самом деле есть. Поэтому невозможно узнать,this[dynamicProp]
существует посредством статического анализа.
Вы можете просто указать машинописному тексту делать то, что вы хотите, (this as any)[dynamicProp]
и он просто проигнорирует это. Но обычно, если вы динамически вычисляете ключи свойств, вы не можете полагаться на статический анализ.