简体   繁体   English

在三元运算符中使用 `enum` TypeScript

[英]Using `enum` in ternary operator TypeScript

I am trying to set an object with a ternary operator based on a config value and an enum我正在尝试使用基于配置值和enum的三元运算符设置 object

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

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

The enum is basically this: enum基本上是这样的:

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

But I get the compilation error:但是我得到编译错误:

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

But I don't understand why it says that the index expression is supposed to be number since is an enum .但我不明白为什么它说索引表达式应该是number ,因为它是一个enum

Can someone explain to me why and how can I achieve what I need?有人可以向我解释为什么以及如何实现我所需要的吗?

Much appreciated.非常感激。

The problem is that config.logLevel is of type string while there is actually only a subset of valid strings.问题是config.logLevelstring类型,而实际上只有一部分有效字符串。

So declare config.logLevel as a union type: 'NOTHING' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'所以将config.logLevel声明为联合类型: 'NOTHING' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' 'NOTHING' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'

This union type doesn't seem to be generatable from the enum according to this: Generic type to get enum keys as union string in typescript?根据以下内容,此联合类型似乎无法从enum中生成: Generic type to get enum keys as union string in typescript?

Related Typescript Playground Example相关Typescript 游乐场示例

Some basics一些基础知识

You can access your enum in different ways:您可以通过不同的方式访问您的枚举:

  1. logLevelEnum.WARN = 2 : by the enum directly logLevelEnum.WARN = 2 : 直接通过枚举
  2. logLevelEnum['WARN'] = 2 : via index operator logLevelEnum['WARN'] = 2 :通过索引运算符
  3. logLevelEnum[2] = WARN : get the enum-name from an enum-value logLevelEnum[2] = WARN :从枚举值中获取枚举名
    This works because typescript creates a reverse mapping这是有效的,因为 typescript 创建了一个反向映射

When you try to access an invalid enum, you get undefined at runtime.当您尝试访问无效枚举时,您会在运行时得到undefined Typescript tries to avoid this situation and gives you a compile error when possible to avoid this: Typescript 试图避免这种情况,并在可能的情况下给你一个编译错误来避免这种情况:

  1. logLevelEnum.warning : Property 'warning' does not exist on type 'typeof logLevelEnum'. logLevelEnum.warning属性“warning”在类型“typeof logLevelEnum”上不存在。
  2. logLevelEnum['warning'] = undefined : Element implicitly has an 'any' type because index expression is not of type 'number'. logLevelEnum['warning'] = undefined元素隐式具有 'any' 类型,因为索引表达式不是 'number' 类型。
    • this is maybe a little confusing, as it seems to indicate that you can only use number as index - which is not true - see 2. above这可能有点令人困惑,因为它似乎表明您只能使用数字作为索引 - 这是不正确的 - 请参见上面的 2.
    • but the basic statement is right: typescript cannot guarantee that this expression returns a valid enum, thus the type of this expression is any (and not logLevelEnum or logLevelEnum | undefined , etc.)但基本语句是正确的: typescript 不能保证这个表达式返回一个有效的枚举,因此这个表达式的类型是any (而不是logLevelEnumlogLevelEnum | undefined等)
      Hint: you can see the type when you hover over the invalidStringIndex variable in the Typescript Playground Example提示:当您在Typescript 游乐场示例中的invalidStringIndex变量上输入 hover 时,您可以看到类型
  3. logLevelEnum[999] = undefined : logLevelEnum[999] = undefined
    • unfortunately we don't get a compile error here, but it is obviously not a valid index不幸的是我们在这里没有得到编译错误,但它显然不是一个有效的索引
    • the type of this expression is string !这个表达式的类型是string But actually it can also be undefined .但实际上它也可以是undefined
      Hint: when you activate the typescript-compiler option noUncheckedIndexedAccess , then the type will be string|undefined which is more accurate提示:当您激活 typescript-compiler 选项noUncheckedIndexedAccess时,类型将是string|undefined这更准确

Answer to your question回答你的问题

As I understand your question据我了解你的问题

  • config.logLevel is of type string and not under your control. config.logLevelstring类型,不受您的控制。
    If it were under your control, the type should be logLevelEnum and everything would be easier: logLevelEnum[logLevelEnum] is then guaranteed to be a valid enum (at compile time)如果它在你的控制之下,类型应该是logLevelEnum并且一切都会更容易:然后保证logLevelEnum[logLevelEnum]是一个有效的枚举(在编译时)
  • you want to get a valid log-level: when config.logLevel is valid, you want to use it, otherwise you want to use logLevelEnum.NOTHING你想获得一个有效的日志级别:当config.logLevel有效时,你想使用它,否则你想使用logLevelEnum.NOTHING

So basically you need a function like this (which you call with config.logLevel ):所以基本上你需要一个像这样的 function(你用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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM