-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Exhaustiveness checking against an enum only works when the enum has >1 member. #23572
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
Comments
This is also the case, when you try to prepare your code for future union types, but currently only use one type. If you uncomment everything regarding the second interface (first 3 comment blocks) everything will work as intended. interface Interface1 {
type: "interface1";
}
// interface Interface2 {
// type: "interface2";
// }
type UnionType = Interface1
// | Interface2;
function calculateFromInterface(i: UnionType): number {
switch (i.type) {
case "interface1":
return 0;
// case "interface2":
// return 1;
}
//Error: 'Argument of type 'Interface1' is not assignable to parameter of type 'never'.'
//typescript version 3.5.1
//however the code can never get to here
assertNever(i);
}
function assertNever(o: never) {
throw "this should never happen";
}
|
Yeah, really it just comes down to "Exhaustiveness checks only work when discriminating against a union with size > 1" |
I just ran into this bug too. Here is a simple example:
|
We also ran into this bug today. Here is another code example, if it can help const rejectUnexpectedValueOfPropertyInObject = (
objectName: string,
propertyName: string,
object: never
): never => {
throw new Error(
`Unexpected value for ${propertyName} in ${objectName}: ${
object && typeof object === "object"
? (object as any)[propertyName]
: "<not an object>"
}`
);
};
type Result =
| {
outcome: "success";
}
// | {
// outcome: "error";
// reason: "reason_2";
// }
| {
outcome: "error";
reason: "reason_1";
};
const f = (a: number, b: number): Result => {
if (a < 0) {
return {
outcome: "error",
reason: "reason_1"
};
}
return { outcome: "success" };
};
const run = (a: number, b: number) => {
const result = f(1, 2);
if (result.outcome === "error") {
switch (result.reason) {
case "reason_1":
console.log("error reason 1");
break;
// case "reason_2":
// console.log("error reason 2");
// break;
default:
rejectUnexpectedValueOfPropertyInObject("result", "reason", result);
}
}
}; The error is
By removing the comments for |
Also ran into this issue today when trying to structure some code for expansion: |
TypeScript Version: [email protected]
Search Terms: discriminated, exhaustiveness, type guard, narrowing
Code
Expected behavior: No error would be thrown, as the switch statement is exhaustive. If the ActionTypes.DECREMENT parts are uncommented (resulting in two possible values for ActionTypes) there is no error. An error only occurs when ActionTypes takes on a single value. The error occurs even if the
never
assertion happens in the default statement, which is obviously unreachable from IIncrement.Actual behavior: An error is thrown despite the only possible value being explicitly handled. If ActionTypes.DECREMENT is uncommented the expected behavior is present.
Playground Link: (fixed the links)
Error
Working
Related Issues:
#19904
#14210
#18056
The text was updated successfully, but these errors were encountered: