This issue has been around for a while, especially with numeric enums. It seems that due to some backwards compatibility concerns, a number
can be assigned to a numeric enum without triggering an error:
enum E {
V = 100
}
const num = 100;
const e: E = num; // no error ðĪ
In addition, numeric enums are designed to function as bit fields, which means they do not restrict the values to only those declared in the enum:
enum Color {
RED = 1,
GREEN = 2,
BLUE = 4
}
const red: Color = Color.RED; // 1
const yellow: Color = Color.RED | Color.GREEN; // 3 ðĪ
const white: Color = Color.RED | Color.GREEN | Color.BLUE; // 7 ðĪ
const octarine: Color = Math.pow(Color.BLUE - Color.RED, Color.GREEN); // 9 ðĪŠ
It's quite strange that you can perform any mathematical operation with a numeric enum. Essentially, any number
can be assigned to any numeric enum, and vice versa.
To avoid this behavior, you might want to consider creating your own types and values with controlled behavior instead of using enums. While more verbose, it can help meet your requirements:
const MyList = {
A: 0,
B: 1
} as const;
type MyList = typeof MyList[keyof typeof MyList]
const MyList2 = {
C: 0
} as const;
type MyList2 = typeof MyList2[keyof typeof MyList2]
These custom types behave similarly to enums but are much stricter about their behavior:
function test<T>(input: MyList | T): void {}
test(0); // okay
test(1); // okay
test(2); // okay, 2 is inferred as T
test<MyList2>(123); // error! 123 is not assignable to 0 | 1
I hope this information is helpful. Best of luck!
Link to code