简体   繁体   English

emberjs glimmer object set() 与变量属性名称

[英]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 的getset函数时。 Specifically, the types for Ember try to make sure you don't end up typo-ing things when doing get and set .具体来说,Ember 的类型试图确保您在执行getset时不会打错字。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM