Typescript 具有变量属性名称的emberjs glimmer对象集()

Typescript 具有变量属性名称的emberjs glimmer对象集(),typescript,ember.js,glimmer.js,Typescript,Ember.js,Glimmer.js,我在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

我在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将设置行标记为错误,特别是propertyName参数。那么如果它能工作,为什么typescript不喜欢它呢


get似乎也出现了这种情况,它不喜欢变量propertyName,比如getthis,propertyName。

通常,如果您的属性被@tracked跟踪,您不需要设置,只需设置[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将无法验证此[dynamicProp]是否实际存在,因为为此它需要执行'data'+1+1;所以它会知道什么是dynamicProp。因此,通过静态分析,我们不可能知道这个[dynamicrop]是否存在

您只需告诉typescript以任何[dynamicrop]的形式执行您想要的操作,它就会忽略它。
但通常,如果动态计算属性键,则不能依赖静态分析。

通常,如果属性被@tracked,则不需要设置,只需执行[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将无法验证此[dynamicProp]是否实际存在,因为为此它需要执行'data'+1+1;所以它会知道什么是dynamicProp。因此,通过静态分析,我们不可能知道这个[dynamicrop]是否存在

您只需告诉typescript以任何[dynamicrop]的形式执行您想要的操作,它就会忽略它。
但通常,如果动态计算属性键,就不能依赖静态分析。

您描述的情况有两个基本问题,其中一个与TypeScript相关,另一个与TypeScript无关

TypeScript的问题是,TS通常知道属性的名称,并且在使用普通的JS属性查找和赋值以及使用Ember的get和set函数时,会检查您是否正确设置了内容。具体来说,Ember的类型试图确保您在执行get和set时不会输入错误。在本例中,您可以看到它们不允许任意字符串的原因:

从“@ember/Component”导入组件; 从'@ember/object'导入{action,set}; 导出默认类Whoops扩展组件{ 问候语=‘你好’; @操作UpdateGreetingEngreeting{ 设置这个“greering”,newGreeting; //--^--打字错误!!! } } 如果set或get的类型只允许任意字符串,那么TS在这里根本帮不了你;它会让错误消失,你必须自己找出错误,而不是让编译器提前告诉你

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

这里有两种改进方法。首先,如果可以的话,您应该弄清楚是否可以将propertyName的类型约束为它来自的类型的keyof。解释keyof超出了这个答案的范围,它将帮助您了解最新情况

但是,第二个问题与更大的问题有关:在讨论这个问题的另一个答案时,您注意到问题在于您试图在单个跟踪根状态上深入设置属性。一般来说,您不应该以这种方式对自动跟踪状态进行变异,因为它是旧的观察者驱动模式的延续,Ember Classic在其计算属性中使用了旧的观察者驱动模式。相反,您更愿意通过该状态的所有者将所有更改驱动到该自动跟踪状态。这样,您就根本不需要设置,系统将自动正确更新


您可以通过使嵌套状态本身自动跟踪、为其定义类或使用类似于包装普通JS对象的方法来实现这一点。无论哪种方式,与其从任何地方进入并深度改变该状态,不如只在拥有该状态的对象上进行。如果您遵循这种模式,并将propertyName约束为OwneroftheState的一个键,其中OwneroftheState是某个类,那么在Ember端和TypeScript端,一切都将“正常工作”。

对于您描述的情况,有两个基本问题,其中一个与TypeScript相关,另一个不相关

类型c 问题是TS通常知道属性的名称,并且在使用普通的JS属性查找和赋值以及使用Ember的get和set函数时,会检查您是否正确设置了属性。具体来说,Ember的类型试图确保您在执行get和set时不会输入错误。在本例中,您可以看到它们不允许任意字符串的原因:

从“@ember/Component”导入组件; 从'@ember/object'导入{action,set}; 导出默认类Whoops扩展组件{ 问候语=‘你好’; @操作UpdateGreetingEngreeting{ 设置这个“greering”,newGreeting; //--^--打字错误!!! } } 如果set或get的类型只允许任意字符串,那么TS在这里根本帮不了你;它会让错误消失,你必须自己找出错误,而不是让编译器提前告诉你

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

这里有两种改进方法。首先,如果可以的话,您应该弄清楚是否可以将propertyName的类型约束为它来自的类型的keyof。解释keyof超出了这个答案的范围,它将帮助您了解最新情况

但是,第二个问题与更大的问题有关:在讨论这个问题的另一个答案时,您注意到问题在于您试图在单个跟踪根状态上深入设置属性。一般来说,您不应该以这种方式对自动跟踪状态进行变异,因为它是旧的观察者驱动模式的延续,Ember Classic在其计算属性中使用了旧的观察者驱动模式。相反,您更愿意通过该状态的所有者将所有更改驱动到该自动跟踪状态。这样,您就根本不需要设置,系统将自动正确更新


您可以通过使嵌套状态本身自动跟踪、为其定义类或使用类似于包装普通JS对象的方法来实现这一点。无论哪种方式,与其从任何地方进入并深度改变该状态,不如只在拥有该状态的对象上进行。如果您遵循这种模式,并将propertyName约束为OwneroftheState的一个键,其中OwneroftheState是某个类,那么无论是在Ember端还是在TypeScript端,一切都将“正常工作”。

您是指Ember 3.15吗?您是指Ember 3.15吗?很高兴知道这一点。我从来没有想过如何通过方括号和typescript一起使用keyaccessor,谢谢。但是,对于这个特定的用例,我的变量是嵌套的跟踪属性。因为它们是嵌套的,根据我的理解,你必须使用set方法来实现余烬魔法,因为仅仅使用@tracked不能处理嵌套属性。也许我可以这样设置,然后使用Ember提供的setPropertyChanged方法。下次我做这个项目的时候,我会试试。注意:1。您不应该为这些设置使用set或setPropertyChanged。相反,您应该重新构建数据建模的方式。如果您需要在更改时更新这些属性,可以更新整个根状态,这意味着:不要在本地对它们进行变异,在拥有它们的类中进行变异,或者直接在拥有该状态的类上对这些属性使用@tracked。2.对于动态道具,不要这样做。相反,可以在本地定义属性,或者使用keyof运算符更具体地说明允许哪些属性名。@ChrisKrycho为什么要特别避免设置?对于我的用例,我正在与第三方api接口,在这里我必须浏览大型、复杂和动态的数据结构。我使用@tracked跟踪所有内容,但其中许多都是从第三方数据复制的复杂对象。@使用set基本上只对您“有效”,因为它是围绕自动跟踪模型工作的。我强烈建议阅读Ember核心团队成员Chris Garrett的文章,了解如何包装其他API,当然细节会因您而异。关键是将第三方API封装在一个能够正确区分“根”状态和“派生”状态的系统中,在这个系统中,根状态是正确的自动跟踪,其他任何人都不知道或考虑这一点。我从来没有想过如何通过方括号和typescript一起使用keyaccessor,谢谢。但是,对于这个特定的用例,我的变量是嵌套的跟踪属性。因为它们是嵌套的,根据我的理解,你必须使用set方法来实现余烬魔法,因为仅仅使用@tracked不能处理嵌套属性。也许我可以这样设置,然后使用Ember提供的setPropertyChanged方法。下次我做这个项目的时候,我会试试。注意:1。您不应该为这些设置使用set或setPropertyChanged。相反,你应该调整你的工作方式
删除你的数据。如果您需要在更改时更新这些属性,可以更新整个根状态,这意味着:不要在本地对它们进行变异,在拥有它们的类中进行变异,或者直接在拥有该状态的类上对这些属性使用@tracked。2.对于动态道具,不要这样做。相反,可以在本地定义属性,或者使用keyof运算符更具体地说明允许哪些属性名。@ChrisKrycho为什么要特别避免设置?对于我的用例,我正在与第三方api接口,在这里我必须浏览大型、复杂和动态的数据结构。我使用@tracked跟踪所有内容,但其中许多都是从第三方数据复制的复杂对象。@使用set基本上只对您“有效”,因为它是围绕自动跟踪模型工作的。我强烈建议阅读Ember核心团队成员Chris Garrett的文章,了解如何包装其他API,当然细节会因您而异。关键是将第三方API封装在一个能够正确区分“根”状态和“派生”状态的系统中,在这个系统中,根状态是正确的自动跟踪,其他任何人都不知道或考虑这一点。