Skip to content

Enums inconsistency #11559

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

Closed
normalser opened this issue Oct 12, 2016 · 5 comments
Closed

Enums inconsistency #11559

normalser opened this issue Oct 12, 2016 · 5 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@normalser
Copy link

normalser commented Oct 12, 2016

In general I thought that using enums is "compatible" with using literal types - (where enums give better support for refactoring, Find all references, intellisense etc.), but seems it's not the case:

Consider the code:

    enum S {
        A, B, C
    }

    type T = 0 | 1 | 2


    function aTest(a: S) {}
    function aTest2(a: S.A | S.B) {}

    function bTest(b: T) {}
    function bTest2(b: 0|1) {}

    aTest(5)  // BAD: Does not throw an error
    aTest2(S.C) // GOOD: Throws an error
    aTest2(5) // BAD: Does not throw an error

    bTest(5) // GOOD: Throws an error
    bTest2(5) // GOOD: Throws an error

    const a:S = 5 // BAD: Does not throw an error
    const b:T = 5 // GOOD: Throws an error

Somewhere deep in the search one can find this explanation (not in the docs) #8020 (comment) that TS does not distinguish between flag and non-flag enums - that's why no errors where one would expect

Maybe it would be worth introducing it ? - because I guess a lot of people would prefer enums to be used as unions and have TS throw an error if someone tries to assign wrong values.

It will be even more inconsistent if string enums will make it to TS: #1206 (comment)

The same example then:

enum S: string {
  A,
  B = "X",
  C
}

type T = 'A' | 'X' | 'C'


function aTest(a: S) {}
function aTest2(a: S.A | S.B) {}

function bTest(b: T) {}
function bTest2(b: 0|1) {}

aTest('W') // GOOD: Error
aTest2(S.C) // GOOD: Error
aTest2('W') // GOOD: Error

bTest(5) // GOOD: Error
bTest2(5) // GOOD: Error

const a:S = "W" // GOOD: Error
const b:T = "W" // GOOD: Error
@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Oct 21, 2016
@dead-claudia
Copy link

Enums are currently number subtypes, so that could be a source of issues.

This in particular seems surprising and really just a bug: aTest(5) should fail regardless.

@normalser
Copy link
Author

Since this is going to be closed soon due to thumbs-down (totally understand braking change) just a quick question - would introducing flag for non-flag enums make sense ? I know you don't want any more flags :D
It's just that probably majority of "normal users" would prefer non-flag enums behavior (unless you are writing compiler ;) - but I might be wrong :) But since it doesn't look like string enums will ever make it - then there won't be any inconsistency in the first place.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Dec 6, 2016

Why not write this?

namespace S {
    export const A = 0;
    export type A = typeof A;
    export const B = 1;
    export type B = typeof B;
    export const C = 2;
    export type C = typeof C;
    // If you need reverse mapping
       Object.entries(S).reduce((result, [key, value]) => {
        result[value] = key;
        return result;
    }, S);
};

type S = S.A | S.B | S.C;
type T = S;

function aTest(a: S) { }
function aTest2(a: S.A | S.B) { }

function bTest(b: T) { }
function bTest2(b: 0 | 1) { }

aTest(5);  // GOOD: Throws an error
aTest2(S.C); // GOOD: Throws an error
aTest2(5); // GOOD: Throws an error

bTest(5); // GOOD: Throws an error
bTest2(5); // GOOD: Throws an error

const a: S = 5; // GOOD: Throws an error
const b: T = 5; // GOOD: Throws an error

@sandersn
Copy link
Member

sandersn commented Dec 6, 2016

@wallverb sadly we tried this a few months ago and it caused breaks on our test corpus. So that's why it got the thumbs down in the backlog slog.

@sandersn sandersn closed this as completed Dec 6, 2016
@RyanCavanaugh RyanCavanaugh added Out of Scope This idea sits outside of the TypeScript language design constraints and removed In Discussion Not yet reached consensus labels Aug 12, 2017
@RyanCavanaugh
Copy link
Member

Not worth the breaking change. Maybe we'll add a flag someday if there turns out to be a lot of demand

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

6 participants