【问题标题】:Using `enum` in ternary operator TypeScript在三元运算符 TypeScript 中使用“枚举”
【发布时间】:2021-08-26 10:02:35
【问题描述】:

我正在尝试使用基于配置值和enum 的三元运算符设置对象

import { config } from 'src/config'
import {logLevelEnum} from 'a-package-installed'

const someObject = {
  logLevel: config.logLevel ? logLevelEnum[config.logLevel] : logLevelEnum.NOTHING,
}

enum 基本上是这样的:

export enum logLevelEnum {
  NOTHING = 0,
  ERROR = 1,
  WARN = 2,
  INFO = 4,
  DEBUG = 5,
}

但我得到编译错误:

Element implicitly has an 'any' type because index expression is not of type 'number'.
logLevel: config.logLevel ? logLevelEnum[config.logLevel] : logLevelEnum.NOTHING,
                                         ~~~~~~~~~~~~~~~

但我不明白为什么它说索引表达式应该是number,因为它是enum

有人可以向我解释为什么以及如何实现我所需要的吗?

非常感谢。

【问题讨论】:

  • 当您声明 logLevel 但将其用作 logLevelEnum 时这是一个错字吗?
  • 您的代码现在确实显示 logLevelEnum 是什么,而不是 config.logLevel 是什么...我猜 config.logLevel 不是数字,但应该是
  • config.logLevel的类型是什么?
  • config.logLevel 是一个字符串,在我使用 TS 之前它工作正常,也许有一个隐式转换?还有关于logLevel 被错误使用,我编辑了,我的错。为了简洁起见,我正在“解释”代码????

标签: javascript typescript enums


【解决方案1】:

问题是config.logLevelstring 类型,而实际上只有一个有效字符串的子集。

所以将config.logLevel 声明为联合类型:'NOTHING' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'

这个联合类型似乎不能从 enum 生成,根据这个:Generic type to get enum keys as union string in typescript?

【讨论】:

  • 我很困惑,如果我把它变成字符串的联合,它仍然是string,但编译器说它应该是number?另一个问题是我无法控制config.level 的类型,所以我不确定在这种情况下该怎么做。
  • 不要介意错误说它应该是number 这不是真的
  • 如果你不控制config.logLevel然后像这样转换类型:logLevelEnum[config.logLevel as 'NOTHING' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG']
【解决方案2】:

相关Typescript Playground Example

一些基础知识

您可以通过不同的方式访问您的枚举:

  1. logLevelEnum.WARN = 2: 直接通过枚举
  2. logLevelEnum['WARN'] = 2:通过索引运算符
  3. logLevelEnum[2] = WARN:从枚举值中获取枚举名称
    这是因为打字稿创建了一个reverse mapping

当您尝试访问无效枚举时,您会在运行时收到 undefined。 Typescript 试图避免这种情况,并在可能的情况下给你一个编译错误以避免这种情况:

  1. logLevelEnum.warning类型“typeof logLevelEnum”上不存在属性“警告”。
  2. logLevelEnum['warning'] = undefined元素隐式具有“任意”类型,因为索引表达式不是“数字”类型。
    • 这可能有点令人困惑,因为它似乎表明您可以 仅使用数字作为索引 - 这是不正确的 - 请参阅上面的 2.
    • 但基本语句是正确的:typescript 不能保证这个表达式返回一个有效的枚举,因此这个表达式的类型是any(而不是logLevelEnumlogLevelEnum | undefined 等)
      提示:当您将鼠标悬停在 Typescript Playground Example 中的 invalidStringIndex 变量上时,您可以看到类型
  3. logLevelEnum[999] = undefined:
    • 很遗憾,这里没有出现编译错误,但它显然不是有效索引
    • 这个表达式的类型是string!但实际上也可以是undefined.
      提示:当您激活 typescript-compiler 选项 noUncheckedIndexedAccess 时,类型将是 string|undefined 更准确

回答您的问题

据我了解您的问题

  • config.logLevel 属于 string 类型,不受您控制。
    如果它在您的控制之下,那么类型应该是 logLevelEnum 并且一切都会变得更容易:logLevelEnum[logLevelEnum] 然后保证是一个有效的枚举(在编译时)
  • 你想得到一个有效的日志级别:当config.logLevel有效时,你想使用它,否则你想使用logLevelEnum.NOTHING

所以基本上你需要一个这样的函数(你用config.logLevel调用):

function getValidLogLevelEnum(logLevelName: string): logLevelEnum {
  /**
   * we need the correct type so that typescript will allow the index access
   * note: we must cast the string to `keyof typeof logLevelEnum`
   *       which resolves to: "NOTHING" | "ERROR" | "WARN" | "INFO" | "DEBUG"
   *       i.e. all valid enum-names
   */
  const enumName = logLevelName as keyof typeof logLevelEnum;
  /**
   * now that we have the correct type of the enum-name, we can get the enum-value
   */
  const configEnum = logLevelEnum[enumName];
  /**
   * keep in mind, that we were cheating a little bit in the type-expression above
   * We told typesript that we are sure that enumName is a valid enum-name,
   * but actually it is just the value of the logLevelName string, which could be anything.
   * Thus, typescript now thinks that configEnum is of type logLevelEnum, but 
   * actually it is `logLevelEnum | undefined` (undefined when logLevelEnum is not a valid enum-name)
   * 
   * This is the reason why use the nullish coalescing operator (??):
   * see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing
   * 
   * so we return configEnum, or logLevelEnum.NOTHING (when configEnum is undefined) 
   */
  return configEnum ?? logLevelEnum.NOTHING;
}

【讨论】:

    猜你喜欢
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 2012-08-10
    • 2020-01-07
    • 2018-05-27
    • 2013-07-06
    相关资源
    最近更新 更多