Skip to content

Any number matches a numeric enum #21546

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
apexskier opened this issue Feb 1, 2018 · 5 comments
Closed

Any number matches a numeric enum #21546

apexskier opened this issue Feb 1, 2018 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@apexskier
Copy link

TypeScript Version: 2.7.1

Search Terms: enum numeric number type

Code

enum TestStringEnum {
    a = "a",
    b = "b",
}

function testStringEnum(test: TestStringEnum) {
    return test;
}

testStringEnum(9); // fails (expected)
testStringEnum("9"); // fails (expected)
testStringEnum(TestStringEnum.a); // passes (expected)
testStringEnum("a"); // fails (???)

type TestNumberUnion = 4 | 5;

function testNumberUnion(test: TestNumberUnion) {
    return test;
}

testNumberUnion(9); // fails (expected)
testNumberUnion("9"); // fails (expected)
testNumberUnion(4); // passes (expected)

enum TestNumberEnum {
    a = 1,
    b = 2,
}

function testNumberEnum(test: TestNumberEnum) {
    return test;
}

testNumberEnum(9); // passes (not expected)
testNumberEnum("9"); // fails (expected)
testNumberEnum(TestNumberEnum.a); // passes (expected)
testNumberEnum(1); // passes (???)

Expected behavior:
The behavior of a string backed enum should match a number backed enum.

Actual behavior:
A number backed enum is treated as equivalent to any number.

Playground Link: playground link

Related Issues:

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Feb 1, 2018
@DanielRosenwasser
Copy link
Member

This is an unfortunate behavior we have due to scenarios where people use enums for things like bit-flags, or other situations where numeric operations on enums should "implicitly" yield other enum members.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 1, 2018

Please see #18409 for more details.

@apexskier
Copy link
Author

I'd expect if someone's using enums for bit flags or are doing numeric operations on them, they'd need to be explicit, in order to prevent holes like the one this issue describes.

For the following (which is currently legal), I'd expect errors when calling isMasked(123, 123) and when doing val & mask.

enum BitMask {
    a = 2,
    b = 4,
}

function isMasked(val: number, mask: BitMask) {
    return val & mask;
}

isMasked(123, 123);
isMasked(123, BitMask.a);

I'd expect this to be the way this works:

enum BitMask {
    a = 2,
    b = 4,
}

function isMasked(val: number, mask: BitMask) {
    return val & (mask as number); // or allow this to work since the compiler knows BitMask is numeric
}

isMasked(123, 123 as BitMask); // 123 isn't a member of BitMask
isMasked(123, BitMask.a);

Currently, there's no way to ensure a parameter is an enum instead of a number if that enum is numeric. From someone who's reading the code's perspective, the type of enum (numeric or string) isn't known.

@apexskier
Copy link
Author

In #18409, there's inconstancy between they way string enums and numeric enums work.

The example given uses strings:

enum Vals {
    ONE = "one",
    TWO = "two",
}

enum AltVals {
    UNO = "one",
}

declare let Vals_ONE: Vals.ONE;
declare let AltVals_Uno: AltVals.UNO;
declare let One: "one";

One = Vals_ONE; // OK
One = AltVals_Uno;  // OK

Vals_ONE = One; // Error
Vals_ONE = AltVals_Uno; // Error

If we switch to numbers, it behaves differently:

enum ValsNumeric {
    ONE = 1,
    TWO = 2,
}

enum AltValsNumeric {
    UNO = 1,
}

declare let ValsNumeric_ONE: ValsNumeric.ONE;
declare let AltValsNumeric_Uno: AltValsNumeric.UNO;
declare let OneNumeric: 1;

OneNumeric = ValsNumeric_ONE; // OK
OneNumeric = AltValsNumeric_Uno;  // OK

ValsNumeric_ONE = OneNumeric; // OK (unexpected) <---------------
ValsNumeric_ONE = AltValsNumeric_Uno; // Error

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants