[英]emberjs glimmer object set() with variable property name
I have a component in Ember 3.15 where I am trying to do something like我在 Ember 3.15 中有一个组件,我正在尝试做类似的事情
import { action, set } from '@ember/object';
@action
someMethod() {
const value = ... // something random
let propertyName = ... // some variable string
set(this, propertyName, value);
}
It seems to be working fine in the browser but typescript is flagging the set line as an error (specifically the propertyName argument).它似乎在浏览器中运行良好,但 typescript 将设置行标记为错误(特别是 propertyName 参数)。 So if it works, why doesn't typescript like it?
那么如果有效,为什么 typescript 不喜欢呢?
This also seems to be happening with get() where it doesn't like variable propertyNames like get(this, propertyName)
.这似乎也发生在 get() 中,它不喜欢像
get(this, propertyName)
这样的变量 propertyNames 。
Generally if your property is @tracked
you dont need set
and can just do this[propertyName] = value;
一般来说,如果你的属性是
@tracked
,你不需要set
,只需这样做this[propertyName] = value;
. .
However your problem is probably a general typescript limitation.但是,您的问题可能是一般的 typescript 限制。 Actual a general problem of static typing:
static打字的一个普遍问题:
Typescript does only static analysis. Typescript 只做 static 分析。 So it does not execute your code.
所以它不会执行你的代码。 So it can not know is a dynamically generated property key actually exists.
所以它无法知道动态生成的属性键是否真的存在。
So if you have something like this:所以如果你有这样的事情:
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]);
}
}
Then typescript will not be able to verify if this[dynamicProp]
actually exists because for this it would need to execute 'data' + (1 + 1);
然后 typescript 将无法验证
this[dynamicProp]
是否确实存在,因为为此它需要执行'data' + (1 + 1);
so it would know what dynamicProp
actually is.所以它会知道
dynamicProp
实际上是什么。 So it is impossible to know if this[dynamicProp]
exists by static analysis.所以通过 static 分析无法知道
this[dynamicProp]
是否存在。
You can just tell typescript to do what you want by (this as any)[dynamicProp]
and it will just ignore it.您可以通过
(this as any)[dynamicProp]
告诉 typescript 做您想做的事情,它会忽略它。 But generally if you dynamically compute property keys you can not rely on static analysis.但通常,如果您动态计算属性键,则不能依赖 static 分析。
There are two basic issues with the situation you have described—one of them related to TypeScript, one of them not.您所描述的情况有两个基本问题 - 其中一个与 TypeScript 有关,其中一个与此无关。
The TypeScript issue is that TS is aware of the names of properties in general, and will check that you're setting things correctly—both when using normal JS property lookup and assignment, and when using Ember's get
and set
functions. TypeScript 的问题是 TS 通常知道属性的名称,并且会检查您是否正确设置了内容——无论是在使用普通 JS 属性查找和赋值时,还是在使用 Ember 的
get
和set
函数时。 Specifically, the types for Ember try to make sure you don't end up typo-ing things when doing get
and set
.具体来说,Ember 的类型试图确保您在执行
get
和set
时不会打错字。 You can see why they don't allow arbitrary strings in this example:您可以在此示例中看到为什么它们不允许任意字符串:
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!!!
}
}
If the types for set
(or get
) just allowed arbitrary strings, TS couldn't help you at all here;如果
set
(或get
)的类型只允许任意字符串,那么 TS 在这里根本帮不了你; it would let it go, and you'd have to figure out the bug yourself—instead of the compiler helpfully telling you about it ahead of time.它会让它成为 go,而且您必须自己找出错误 - 而不是编译器会帮助您提前告诉您。
In the case you're running into, TypeScript presumably just sees a string , and it says “I don't have any way to check if this string belongs to the property.”在您遇到的情况下, TypeScript 可能只是看到一个字符串,它说“我没有任何方法可以检查这个字符串是否属于该属性。”
There are a couple ways to improve things here.这里有几种改进方法。 First of all, if you can, you should figure out if it's possible to constrain the type of
propertyName
to be a keyof
for the type it's coming from.首先,如果可以,您应该弄清楚是否可以将
propertyName
的类型限制为它来自的类型的keyof
。 (Explaining keyof
is beyond the scope of this answer, this section in the handbook and this blog post will get you up to speed.) (解释
keyof
超出了这个答案的 scope , 手册中的这一部分和这篇博文将让你快速上手。)
Second, though, and connected to the bigger issue: you noted in discussion to the other answer on this question that the problem is that you're trying to deeply set properties on a single piece of tracked root state.其次,与更大的问题有关:您在讨论该问题的另一个答案时指出,问题是您正试图在单个跟踪根 state 上深入设置属性。 In general, you should not mutate autotracked state this way—it's a holdover from the old observers-driven patterns that Ember Classic used with its computed properties.
通常,您不应该以这种方式改变自动跟踪的 state - 这是 Ember Classic 使用其计算属性的旧观察者驱动模式的保留。 Instead, prefer to drive all changes to that autotracked state through the owner of that state.
相反,更愿意通过 state 的所有者来驱动对自动跟踪的 state 的所有更改。 Then you won't need
set
at all, and the system will update correctly automatically.那么你根本不需要
set
,系统会自动正确更新。
You can do that either by making the nested state itself be autotracked, either by defining a class for it or by using something like tracked-built-ins to wrap a plain JS object.您可以通过为嵌套 state本身自动跟踪来做到这一点,方法是为其定义一个 class 或使用类似跟踪内置插件的东西来包装一个普通的 JS ZA8CFDE6331BD59EB2AC96F8911C4B666 Either way, instead of reaching in and deeply mutating that state from just anywhere, do it only on the object that owns that state.
无论哪种方式,与其从任何地方深入并深入变异 state,不如仅在拥有该 state 的 object 上执行此操作。 If you follow that pattern, and constrain the
propertyName
to be a keyof TheOwnerOfTheState
where TheOwnerOfTheState
is some class, everything will “just work”—both on the Ember side and the TypeScript side.如果您遵循该模式,并将
propertyName
限制为keyof TheOwnerOfTheState
的键,其中TheOwnerOfTheState
是某个 class,那么在 Ember 端和 TypeScript 端,一切都将“正常工作”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.