Skip to content

TypeScript "forgets" enum in mapped type key #52251

@ddurschlag

Description

@ddurschlag

Bug Report

Enum values can be used on both sides of a mapped type (key/value). For values, things work great! For keys, the enum is "forgotten" and replaced with its integral value. This can cause problem for further type logic.

🔎 Search Terms

Enum, Mapped Type

🕗 Version & Regression Information

Replicated in playground in 3.3.3333, 4.9.4, and nightly.

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about enums and mapped types
  • I was unable to test this on prior versions because playground only goes back to 3.3.3333

⏯ Playground Link

https://tinyurl.com/mwee547u

💻 Code

enum MyEnum {
    MyEnumValue
};

type EnumOnBothMapSides = {[MyEnum.MyEnumValue]: MyEnum.MyEnumValue};
/*
EnumOnBothMapSides inferred as:

type EnumOnBothMapSides = {
    0: MyEnum.MyEnumValue;
}

Notice that the enum-ness has been lost in the key
*/
type EnumValueType = typeof MyEnum[MyEnum.MyEnumValue];
/*
EnumValueType inferred as:

type EnumValueType = string

It would be nice if this were "MyEnumValue", but that's more of a feature request than a bug.
Nonetheless, we now know that indexing into MyEnum with MyEnumValue produces a string.
Let's specify that:
*/
type MyEnumIndex = {[MyEnum.MyEnumValue]: string};
/*
MyEnumIndex inferred as:

type MyEnumIndex = {
    0: string;
}

This replicates the "forgetfulenss" seen above.
*/
const myEnumIndex: MyEnumIndex = MyEnum;
/*
Error:

Property '[MyEnum.MyEnumValue]' is missing in type 'typeof MyEnum' but required in type 'MyEnumIndex'.(2741)
Earlier, however, TypeScript was quite explicit that "typeof MyEnum[MyEnum.MyEnumValue]" is a string.
*/

🙁 Actual behavior

myEnumIndex doesn't typecheck.

🙂 Expected behavior

myEnumIndex typechecks, as its type describes a demonstrable behavior of the enum type. This should be, in effect, a widening/covariant conversion which TS is generally ok with.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions