TypeScript Version:
3.2.1, plus whatever runs on typescriptlang.org playground.
Search Terms:
enum, enum comparable
Code
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
See Playground Link.
Expected behavior:
No error.
Actual behavior:
Error:() TS2678: Type 'Backend.kinvey' is not comparable to type 'Backend.static'.
Playground Link:
https://www.typescriptlang.org/play/index.html#src=enum%20Backend%20%7B%0D%0A%20%20%20%20%20%20%20%20url%2C%0D%0A%20%20%20%20%20%20%20%20kinvey%2C%0D%0A%20%20%20%20%20%20%20%20static%0D%0A%7D%0D%0A%20%20%20%20%0D%0Avar%20backend%3A%20Backend%3B%0D%0A%0D%0Abackend%20%3D%20Backend.static%3B%0D%0Acompare()%3B%0D%0A%0D%0Afunction%20compare()%20%7B%0D%0A%20%20%20%20backend%20%3D%20Backend.static%3B%0D%0A%0D%0A%20%20%20%20switch%20(backend)%20%7B%0D%0A%20%20%20%20%20%20%20%20case%20Backend.static%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%0D%0A%20%20%20%20%20%20%20%20case%20Backend.kinvey%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%0D%0A%20%20%20%20%20%20%20%20case%20Backend.url%3A%0D%0A%20%20%20%20%20%20%20%20default%3A%0D%0A%20%20%20%20%20%20%20%20%2F%2F%0D%0A%20%20%20%20%7D%0D%0A%7D
Related Issues:
Of course in the example some branches of the Switch are unreachable but that should not throw an error. If you delete the statement "backend = Backend.static;" on line 13, while keep the same statement outside the function on line 9, the situation is identical but no error is thrown.
You assigned backend to Backend.static just before the switch, so typescript knows that has that value and warns you that can not has any other value than Backend.static. Change the assignment before switch to backend = Backend.static as any; as a workaround.
Removing that assignment remove the errors because the value can change before calling the function compare.
What is the point of TypeScript compiler linting the code? Also, I am not getting a warning, I am getting an error.
All TypeScript errors are warnings by definition because it still emits code (unless you use --noEmitOnError)
This issue is a breaking change to our code base.
The issue runs deeper than shown in the original sample code.
Basically, even if you have a function call in between setting the variable and reading it which changes the enum value internally,
the compiler still thinks that the type can only be the specific value that was set locally,
(even though the type was "defined" as being the enum "union type").
This is causing our unit tests to fail in our project.
Imagine this unit test in an angular app:
it('updates display state to Preview', () => {
// start in "edit mode"
component.displayState = DisplayState.Edit;
// change the `component.displayState` to `DisplayState.Preview`
triggerUserClickPreviewButton();
// this is throwing error: Argument of type 'DisplayState.Edit' is not assignable to parameter of type 'Expected<DisplayState.Preview>'.
expect(component.displayState).toEqual(DisplayState.Preview);
});
I have extended to previous example of how this gives a false "error" here:
@ahejlsberg If this is intended, what is the point? Why are the Enum's constants considered a type instead of a value? (_Error:() TS2678: Type 'x' is not comparable to type 'y'_)
And if they are considered a type, not a value, why do we not get an error when we set the type across functions? And why do we not get the error only from switch comparison but not from if comparison?
Itβs a type for the same reason as:
let x: 1 | 2 | 3 = 1;
x = 4; // error
See #9998 for a lengthy discussion on this topic.
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
Β―_(γ)_/Β―
To summarize the points in #9998: Canceling type narrowings across a function call causes more problems than not doing so, so the current behavior is the lesser of two evils. A comprehensive analysis of the code is not possible (or at least not practical).
Most helpful comment
To summarize the points in #9998: Canceling type narrowings across a function call causes more problems than not doing so, so the current behavior is the lesser of two evils. A comprehensive analysis of the code is not possible (or at least not practical).