ember.js 带有变量属性名称的emberjs glimme对象set()

tyg4sfes  于 2022-11-05  发布在  其他
关注(0)|答案(2)|浏览(136)

我在Ember 3.15中有一个组件,我尝试在其中执行以下操作

import { action, set } from '@ember/object';

@action
someMethod() {
  const value = ... // something random
  let propertyName = ... // some variable string
  set(this, propertyName, value);
}

它在浏览器中看起来工作正常,但是typescript将set行标记为错误(特别是propertyName参数)。那么,如果它工作正常,为什么typescript不喜欢它呢?
这似乎也发生在get()中,它不喜欢get(this, propertyName)这样的变量propertyNames。

nhhxz33t

nhhxz33t1#

一般来说,如果你的属性是@tracked,你不需要set,可以只做this[propertyName] = value;
然而,你的问题可能是一个通用的打字脚本限制。实际上,静态类型的一个通用问题是:
Typescript只做静态分析。所以它不执行你的代码。所以它不能知道一个动态生成的属性键是否真的存在。
所以如果你有这样的东西:

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]);
  }
}

然后typescript将无法验证this[dynamicProp]是否实际存在,因为为此它需要 * 执行 * 'data' + (1 + 1);,这样它才能知道dynamicProp实际是什么。因此,通过静态分析来知道this[dynamicProp]是否存在是 * 不可能的 *。
你可以通过(this as any)[dynamicProp]命令typescript做你想做的事情,它会忽略它。但是通常如果你动态计算属性键,你就不能依赖静态分析。

camsedfj

camsedfj2#

您所描述的情况有两个基本问题--一个与TypeScript有关,另一个与之无关。
TypeScript的问题是TS通常知道属性的名称,并且会检查您是否正确设置了内容--无论是在使用普通的JS属性查找和赋值时,还是在使用Ember的getset函数时。Ember的类型试图确保在执行getset时不会出现输入错误。在下面的示例中,您可以看到它们不允许任意字符串的原因:

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在这里一点帮助也没有;它会让它过去,您必须自己找出bug-而不是编译器提前告诉您。
在您遇到的情况下,TypeScript可能只看到了一个 string,它说“我没有任何方法来检查这个字符串是否属于该属性”。
这里有几种方法可以改进。首先,如果可以的话,您应该弄清楚是否可以将propertyName的类型约束为keyof。(解释keyof超出了本答案的范围,this section in the handbookthis blog post将帮助您了解最新情况。)
第二个问题与更大的问题有关:您在讨论这个问题的另一个答案时注意到,问题在于您试图在单个跟踪的根状态上深入设置属性。一般来说,您 * 不 * 应该以这种方式改变自动跟踪的状态--这是旧的观察者驱动模式的遗留问题,EmberClassic使用它的计算属性。相反,我更喜欢通过状态的 owner 驱动对自动跟踪状态的所有更改。这样你就根本不需要set了,系统会自动正确更新。
您可以通过自动跟踪嵌套状态 * 本身 * 来实现这一点,也可以为它定义一个类,或者使用类似tracked-built-ins的东西来 Package 一个普通的JS对象。无论哪种方式,都不是从任何地方深入修改该状态,而是 * 只 * 在拥有该状态的对象上进行。如果您遵循这种模式,并将propertyName约束为keyof TheOwnerOfTheState,其中TheOwnerOfTheState是某个类,则一切都将“正常工作”--无论是在Ember端还是在TypeScript端。

相关问题