I am trying to set an object with a ternary operator based on a config value and an enum
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:
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
.
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.
So declare config.logLevel
as a union type: '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?
Related Typescript Playground Example
You can access your enum in different ways:
logLevelEnum.WARN
= 2
: by the enum directly logLevelEnum['WARN']
= 2
: via index operator logLevelEnum[2]
= WARN
: get the enum-name from an enum-value When you try to access an invalid enum, you get undefined
at runtime. Typescript tries to avoid this situation and gives you a compile error when possible to avoid this:
logLevelEnum.warning
: Property 'warning' does not exist on type 'typeof logLevelEnum'. logLevelEnum['warning']
= undefined
: Element implicitly has an 'any' type because index expression is not of type 'number'.
any
(and not logLevelEnum
or logLevelEnum | undefined
, etc.)invalidStringIndex
variable in the Typescript Playground ExamplelogLevelEnum[999]
= undefined
:
string
! But actually it can also be undefined
.string|undefined
which is more accurateAs I understand your question
config.logLevel
is of type string
and not under your control. logLevelEnum
and everything would be easier: logLevelEnum[logLevelEnum]
is then guaranteed to be a valid enum (at compile time)config.logLevel
is valid, you want to use it, otherwise you want to use logLevelEnum.NOTHING
So basically you need a function like this (which you call with 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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.