首页 > 解决方案 > 具有可变属性名称的 emberjs glimmer 对象 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 like get(this, propertyName)

标签: typescriptember.jsglimmer.js

解决方案


您所描述的情况有两个基本问题——一个与 TypeScript 相关,一个与 TypeScript 无关。

TypeScript 的问题是 TS 通常知道属性的名称,并会检查您是否正确设置了内容——无论是在使用普通 JS 属性查找和赋值时,还是在使用 Embergetset函数时。具体来说,Ember 的类型试图确保您在执行getand时不会出现拼写错误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(or get) 的类型只允许任意字符串,那么 TS 在这里根本帮不了你;它会放过它,您必须自己找出错误,而不是编译器提前告诉您有关它的有用信息。

在你遇到的情况下,TypeScript 可能只是看到一个字符串,它说“我没有任何方法可以检查这个字符串是否属于该属性。”</p>

这里有几种改进方法。首先,如果可以的话,你应该弄清楚是否可以将类型限制propertyNamekeyof它来自的类型。(解释keyof超出了这个答案的范围,手册中的这一部分这篇博客文章会让你快速上手。)

其次,与更大的问题有关:您在讨论该问题的另一个答案时指出,问题在于您正试图在单个跟踪的根状态上深入设置属性。一般来说,你不应该以这种方式改变自动跟踪状态——它是旧的观察者驱动模式的遗留物,Ember Classic 使用它的计算属性。相反,更愿意通过该状态的所有者来驱动对该自动跟踪状态的所有更改。然后你根本不需要set,系统会自动正确更新。

您可以通过自动跟踪嵌套状态本身来做到这一点,或者为它定义一个类,或者使用类似tracked-built-ins之类的东西来包装一个普通的 JS 对象。无论哪种方式,与其从任何地方进入并深度改变该状态,不如在拥有该状态的对象上执行。如果您遵循该模式,并将 限制为某个类的位置,那么一切都会“正常工作”——propertyName无论是在 Ember 端还是在 TypeScript 端。keyof TheOwnerOfTheStateTheOwnerOfTheState


推荐阅读