TypeScript Version: 3.5.0-dev.20190514
Search Terms: undefined discriminated union discriminant discriminator unions type guard control flow narrowing
Code
// --strictNullChecks
interface Option1 {
x: true;
}
interface Option2 {
x: false | undefined;
}
type OptionUnion = Option1 | Option2;
function acceptOption1(x: Option1): void {}
function acceptOption2(x: Option2): void {}
function acceptNever(x: never): void {}
function test(anOption: OptionUnion): void {
if (anOption.x === true) {
acceptOption1(anOption);
} else if (anOption.x === false || anOption.x === undefined) {
acceptOption2(anOption);
} else {
acceptNever(anOption);
}
}
Expected behavior:
No errors.
Actual behavior:
acceptNever(anOption); has an error: Argument of type 'Option2' is not assignable to parameter of type 'never'. ts(2345)
Note that the code works correctly if the discriminator is not a property:
// --strictNullChecks
type Option1 = true;
type Option2 = false | undefined;
type OptionUnion = Option1 | Option2;
function acceptOption1(x: Option1): void {}
function acceptOption2(x: Option2): void {}
function acceptNever(x: never): void {}
function test(anOption: OptionUnion): void {
if (anOption === true) {
acceptOption1(anOption);
} else if (anOption === false || anOption === undefined) {
acceptOption2(anOption);
} else {
acceptNever(anOption); // Not an error - correctly narrows to `never`
}
}
Playground Link:
http://www.typescriptlang.org/play/index.html#src=%2F%2F%20--strictNullChecks%0D%0A%0D%0Ainterface%20Option1%20%7B%0D%0A%09x%3A%20true%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20Option2%20%7B%0D%0A%09x%3A%20false%20%7C%20undefined%3B%0D%0A%7D%0D%0A%0D%0Atype%20OptionUnion%20%3D%20Option1%20%7C%20Option2%3B%0D%0A%0D%0Afunction%20acceptOption1(x%3A%20Option1)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20acceptOption2(x%3A%20Option2)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20acceptNever(x%3A%20never)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20test(anOption%3A%20OptionUnion)%3A%20void%20%7B%0D%0A%09if%20(anOption.x%20%3D%3D%3D%20true)%20%7B%0D%0A%09%09acceptOption1(anOption)%3B%0D%0A%09%7D%20else%20if%20(anOption.x%20%3D%3D%3D%20false%20%7C%7C%20anOption.x%20%3D%3D%3D%20undefined)%20%7B%0D%0A%09%09acceptOption2(anOption)%3B%0D%0A%09%7D%20else%20%7B%0D%0A%09%09acceptNever(anOption)%3B%0D%0A%09%7D%0D%0A%7D%0D%0A
Related Issues:
#14471 is also using undefined as a discriminant, although the linked issue is restricting itself to talking about mapped types
TypeScript Version: 3.5.0-dev.20190514
Search Terms: undefined discriminated union discriminant discriminator unions type guard control flow narrowing
Code
Expected behavior:
No errors.
Actual behavior:
acceptNever(anOption);has an error:Argument of type 'Option2' is not assignable to parameter of type 'never'. ts(2345)Note that the code works correctly if the discriminator is not a property:
Playground Link:
http://www.typescriptlang.org/play/index.html#src=%2F%2F%20--strictNullChecks%0D%0A%0D%0Ainterface%20Option1%20%7B%0D%0A%09x%3A%20true%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20Option2%20%7B%0D%0A%09x%3A%20false%20%7C%20undefined%3B%0D%0A%7D%0D%0A%0D%0Atype%20OptionUnion%20%3D%20Option1%20%7C%20Option2%3B%0D%0A%0D%0Afunction%20acceptOption1(x%3A%20Option1)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20acceptOption2(x%3A%20Option2)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20acceptNever(x%3A%20never)%3A%20void%20%7B%7D%0D%0A%0D%0Afunction%20test(anOption%3A%20OptionUnion)%3A%20void%20%7B%0D%0A%09if%20(anOption.x%20%3D%3D%3D%20true)%20%7B%0D%0A%09%09acceptOption1(anOption)%3B%0D%0A%09%7D%20else%20if%20(anOption.x%20%3D%3D%3D%20false%20%7C%7C%20anOption.x%20%3D%3D%3D%20undefined)%20%7B%0D%0A%09%09acceptOption2(anOption)%3B%0D%0A%09%7D%20else%20%7B%0D%0A%09%09acceptNever(anOption)%3B%0D%0A%09%7D%0D%0A%7D%0D%0A
Related Issues:
#14471 is also using
undefinedas a discriminant, although the linked issue is restricting itself to talking about mapped types