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
Reactions are currently unavailable
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