Using enums as types allows values that don’t exist in the enum

(update 2021-06-10, this is unchanged by the TS4.3 update for union enums)

This is (maybe surprisingly) intended behavior. Numeric enums in TypeScript are sometimes used for bitwise operations, where the listed values are treated as flags. And, as stated by @RyanCavanaugh in a comment on a reported issue about this:

We don’t distinguish between flag and non-flag enums, so a number that is above [or not equal to] any given enum member isn’t necessarily invalid. For example

enum Flags {
Neat = 1,
Cool = 2,
Great = 4
}
// like saying Neat | Cool | Great
var x: Flags = 7;

So even though 7 is not equal to any one of the listed Flags enum values, you can still get it by performing bitwise operations of the listed values. I’m pretty sure that the compiler doesn’t do any restriction other than checking that the value is a number.

In your case, even though none of the Something enumerated values are 15, it doesn’t stop you from doing the (useless and dubiously sane) following:

const value: Something = (Something.Email | Something.All) >> 1;

which amounts to the same thing (10 | 20 evaluates to 30, and 30 >> 1 is 15).


Note that this bitwise stuff doesn’t apply to string-based enums, so one way to deal with this is to change your numbers to string literals:

const enum Something {
  None="0",
  Email="10",
  All="20"
}
const value: Something = '15'; // error, as desired

and the compiler warns you that '15' is not a valid value for Something.

Hope that helps. Good luck!

Leave a Comment