Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enums can not be used for index signature types #13042

Closed
ChiriVulpes opened this issue Dec 20, 2016 · 21 comments
Closed

Enums can not be used for index signature types #13042

ChiriVulpes opened this issue Dec 20, 2016 · 21 comments
Assignees
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@ChiriVulpes
Copy link

ChiriVulpes commented Dec 20, 2016

TypeScript Version: 2.1.4

export interface UserInterfaceColors {
    [index in UserInterfaceElement]: ColorInfo;
}
export interface ColorInfo {
    r: number;
    g: number;
    b: number;
    a: number;
}
export enum UserInterfaceElement {
    ActiveTitleBar = 0,
    InactiveTitleBar = 1,
}

Expected behavior:
No errors will be thrown.

Actual behavior:
index in UserInterfaceElement throws the error Type 'UserInterfaceElement' is not assignable to type 'string'

This is a regression caused by #12425. The change makes sense, but there are very valid use cases for supporting enums in index signatures.

For another use case, in a project I'm working on, we use an enum to list all types of items. We have a function that takes an object with the enum values as keys, and data as values.

function loadItemData (data: { [index in ItemType]: string }): void;

A workaround is to use index: number, but then it's not enforced that you have to use a valid ItemType as a key.

Original Issue: #2491

@mhegazy mhegazy added In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Dec 20, 2016
@zpdDG4gta8XKpMCd
Copy link

can we allow string & Whatever for index signatures too?

@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Jan 24, 2017
@RyanCavanaugh
Copy link
Member

Approved.

Note that this will not cause nominal enforcement of enum index expressions!

Specifically, [index in UserInterfaceElement]: ColorInfo; will eagerly reduce to "0" | "1" : ColorInfo, so indexing by any other 0- or 1-valued enum value will not cause an error.

@amitbeck
Copy link

Thanks for handling this! Waiting for the fix 👍🏻

@amitbeck
Copy link

@augusto-moura Looks like it's been moved from milestone TypeScript 2.6 to TypeScript 2.7 as seen above 😞

@yordis
Copy link

yordis commented Jan 14, 2018

@sandersn do you know when could we have this released?

@aselbie
Copy link

aselbie commented Jan 15, 2018

@yordis Not sure, but looks like it got bumped back to 2.8, so probably at least another 3 months.

@yordis
Copy link

yordis commented Jan 15, 2018

😭 <---- I need it in the Reactions

@kompot
Copy link

kompot commented Feb 20, 2018

I'm not sure why and how but it started working for me (2.7.1).

So a long awaited (by me ;) feature of enum exhaustive checking finally works.

Given

enum X {
  Y = 'y',
  Z = 'z',
}

type A = { [TKey in X]: string };

the following is ok

const a: A = {
  [X.Y]: 'x',
  [X.Z]: 'x',
}

but this is compile time error

const a: A = {
  [X.Y]: 'x',
}

@ChiriVulpes
Copy link
Author

ChiriVulpes commented Feb 20, 2018

@kompot That's because you're mapping the enums to string values. You're really just using strings as keys. This issue is for the use of numeric enum entries (which would allow auto-assigned enums to work as well)

As far as I know, it's worked via string since in and string enums were both present in the language.

@kompot
Copy link

kompot commented Feb 20, 2018

Well, it definitely didn't work like 6 months ago when I was banging my head trying to get some concise way of exhaustive enum checking. I understand that this is a different issue, yes. But from my understanding getting it work with auto-assigned enums is not that critical when mapped strings enums work this nice.

@mhegazy mhegazy changed the title Enums can no longer be used for index signature types Enums can not be used for index signature types Feb 20, 2018
@mhegazy mhegazy modified the milestones: TypeScript 2.8, TypeScript 2.9 Mar 9, 2018
@bsdunx
Copy link

bsdunx commented Mar 11, 2018

       const enum UnitType {
              PLAYER = 0x01,
              MONSTER = 0x02
       }
       const descriptor = ({
            [UnitType.PLAYER as number]: Player.descriptor,
            [UnitType.MONSTER as number]: Monster.descriptor
        })[type]

Doing it like so may help some in the interim

@mhegazy
Copy link
Contributor

mhegazy commented Apr 26, 2018

Should be fixed by #23592

@mhegazy mhegazy closed this as completed Apr 26, 2018
@gyandeeps
Copy link

Was this actually fixed by #23592 ?
Using TS 2.9.1,

enum Test {
    A = "a",
    B = "b"
}
export interface PhaseApi1 {
    [x in Test]: () => void;
}

still have issues

* A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
* A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
* Cannot find name 'x'.

Playground link

@mhegazy
Copy link
Contributor

mhegazy commented May 31, 2018

enum Test {
    A = "a",
    B = "b"
}
type PhaseApi1 = {
    [x in Test]: () => void;
};

@timkinnane
Copy link

Just a postmortem FYI for anyone who's gone through what I did, trying for hours to solve this with all manner of type rejigging to remove index signature errors... Make sure your IDE linter has the latest version of Typescript. Those errors might not actually be errors at all.

+1 for the 😭 reaction option.

@aboyton
Copy link

aboyton commented Aug 7, 2018

@mhegazy Any reason that this works for type and not interface? I know it's easy to use one over the other but it seems a strange restriction.

@VitamintK
Copy link

It's unlikely that this happens to anyone else but me, but if you're trying to figure out why the fix isn't working for you, check that you spelled your enum correctly.

@kg-currenxie
Copy link

enum Test {
    A = "a",
    B = "b"
}
type PhaseApi1 = {
    [x in Test]: () => void;
};

Is there a way to make either key optional?

@ChiriVulpes
Copy link
Author

@kg-currenxie

type PhaseApi1 = {
    [x in Test]?: () => void;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests