Description
TypeScript Version:
3.8.0-dev.20191121
Search Terms:
- refinement
- guard
Code
interface A<T> {
variant: 'a'
value: T
}
interface B<T> {
variant: 'b'
value: Array<T>
}
type AB<T> = A<T> | B<T>
function printValue<T>(t: T): void {
console.log(t)
}
function printValueList<T>(t: Array<T>): void {
console.log(t)
}
function unrefined1<T>(ab: AB<T>): void {
const { variant, value } = ab
if (variant === 'a') {
printValue<T>(value)
} else {
printValueList<T>(value)
}
}
function unrefined2<T>(ab: AB<T>): void {
const { variant } = ab
if (variant === 'a') {
const { value } = ab
printValue<T>(value)
} else {
const { value } = ab
printValueList<T>(value)
}
}
function refined<T>(ab: AB<T>): void {
if (ab.variant === 'a') {
const { value } = ab
printValue<T>(value)
} else {
const { value } = ab
printValueList<T>(value)
}
}
Expected behavior:
A destructured shared field of a discriminated union should be refined inside of a block that refines the discriminated union itself. I think the code example explains what I'd expect to happen better than I can in words.
Actual behavior:
Variables that are destructured prior to the union being refined are still stuck as unions within a block where the discriminated union is refined.
Additional comments:
- For what it's worth, the code example above is still valid without a type parameter i.e. a concrete type where
T
would be - I can't think of any scenario where the destructured value would not be correctly refined if this behavior were implemented.
Related Issues:
I couldn't find any open issues regarding object destructuring and type guards, but these were the only two closest to the issue I'm seeing.
#18840 - Type guards on variable break refinements on its properties
#20504 - Nested if statement invalidates type guards