【问题标题】:Iterate on string enum迭代字符串枚举
【发布时间】:2018-06-02 11:22:01
【问题描述】:

我一定遗漏了一些东西,但我找到了几种方法来遍历枚举而不是字符串枚举。

给出以下枚举:

export enum Locales {
  En = 'en',
  Fr = 'fr',
  De = 'de',
  Es = 'es',
  It = 'it',
  Nl = 'nl',
  No = 'no',
  Tr = 'tr',
}

我想要达到的目标:

我想迭代那个字符串枚举,以便获得值(!)。我试过的:

for (const key of Object.keys(Locales)) {
  const locale: string = Locales[key];
  console.log(locale); // Should print 'en', 'fr' and so on
}

上面代码的问题:

由于严格的 tsconfig(不允许隐式任何),我无法将其编译为 javascript。由于这不是我的项目,我也无法更改此 tsconfig。它突出显示了Locales[key] 处的key 变量,这个错误对我来说很有意义:

[ts] 元素隐含地具有“任何”类型,因为索引表达式是 不是“数字”类型。

问题:

使用 Typescript 2.6+ 迭代字符串枚举以获取其值的正确方法是什么?

【问题讨论】:

  • 使用 - keyof typeof Locales - 将给出枚举成员的枚举类型,该类型可用于断言键的类型 - Locales[key as keyof typeof Locales]。

标签: node.js typescript


【解决方案1】:

正如 betadeveloper 所建议的,如果您使用类型断言 as keyof typeof Locales,您可以获得正确的密钥类型。或者您可以将其包装在 Object.keys() 函数的类型安全变体中,如下所示:

export enum Locales {
  En = 'en',
  Fr = 'fr',
  De = 'de',
  Es = 'es',
  It = 'it',
  Nl = 'nl',
  No = 'no',
  Tr = 'tr',
}

function enumKeys<E>(e: E): (keyof E)[] {
  return Object.keys(e) as (keyof E)[];
}

for (const key of enumKeys(Locales)) {
  const locale: string = Locales[key];
  console.log(locale); 
}

另外,作为记录,旧式 for .. in 循环仍然有效:

for (let key in Locales) {
    let locale = Locales[key];
    console.log(locale);
}

【讨论】:

  • 有人告诉我我不应该使用for in 循环,因此项目的 tslint 配置现在不满意。 [tslint] for (... in ...) statements must be filtered with an if statement (forin)[tslint] Do not use the 'for in' statement: 'for (const key in Locales)'. If this is an object, use 'Object.keys' instead. If this is an array use a standard 'for' loop instead. (no-for-in)。另外我看不出这对我有什么帮助,因为我也会有同样的问题(索引字符串)?在我给定的示例中,我还尝试将 key 转换为字符串,这当然不会改变任何内容
  • 它会有所帮助(如果不是因为您的 tslint 配置),因为它在严格模式下编译时不会出错。
  • 好的同意这一点,但是我很惊讶打字稿编译这个。在您的情况下,语言环境只是另一个字符串(就像在我给定的示例中一样)。你能解释一下为什么 typescript 编译你的例子而它不会编译我的代码(它也使用字符串作为索引)吗?
  • 不知道如何解释它,可能是因为编译器在for .. in 循环中为key 推断出正确的类型(keyof typeof Locales,而不是string)。 @betadeveloper 的建议更好——我正在更新答案
  • keyof typeof Locales 有效,keyof Locales 无效。
【解决方案2】:

@Artem 和@betadeveloper 指出我可以使用keyof typeof Locales 类型作为我的方法。我最终想出的解决方案是这样的:

const keys: (keyof typeof Locales)[] = <(keyof typeof Locales)[]>Object.keys(Locales);
for (const key of keys) {
  const locale: string = Locales[key];
  console.log(locale); // Prints 'en', 'fr' and so on
}

【讨论】:

  • 如果旧式 for .. in 循环仍然像 artem 提到的那样工作,为什么不使用它呢?我建议尽可能避免丑陋的类 C++ 类型转换。
  • 如前所述,这不是我的项目,因此也不是我的 tslint。我们正在使用微软的 contrib tslint,可以在这里找到:github.com/Microsoft/tslint-microsoft-contrib。过去我注意到他们的规则集通常总是有充分的理由,所以我也更喜欢遵守这些规则。我在上面所做的实际上与 artem 建议的 Typescript 2+ 样式相同,并且遵循 microsoft tslint 指南。
  • 这很痛苦,我希望它更容易,但这很好用
  • &lt;&gt; 转换似乎也被 Angular 9 中的no-angle-bracket-type-assertion TSLint 规则所阻止。您也可以删除类型提示,因为类型会被推断出来。这样第一行就变成了:const keys = Object.keys(Locales) as (keyof typeof Locales)[];,看起来还不错,并且让 linter 很开心。
  • 这个答案就像我生命中的天使......谢谢。
【解决方案3】:

洛达什

Lodash 是一个很好的选择,因为它易于使用并提供易于理解的 api。在 lodash 方法中,forIn 是您正在寻找的选项。要获取typescript declaration files,可以安装:

npm install @types/lodash

使用forIn 方法,您可以获得Locales 对象的valuekey

import { forIn } from 'lodash'

enum Locales {
  En = 'en',
  Fr = 'fr'
  // ...
}

forIn(Locales, (value, key) => console.log(value, key))

【讨论】:

    【解决方案4】:

    添加这个问题是因为我正在寻找解决方案。

    最好的解决办法是使用Object.values()https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

    Object.values(Locales).forEach((locale) => console.log(locale));
    
    // or
    
    for (const locale of Object.values(Locales)) {
      console.log(locale);
    }
    

    还可以考虑Object.entries() 来获取字符串值枚举的键和值。

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      相关资源
      最近更新 更多