Say I have a function like this:
function foo(n: number): [number, undefined] | [undefined, number] {
if (n % 2 === 0) {
return [n, undefined];
}
return [undefined, n];
}
And then calling this function like this:
function bar() {
const [a, b] = foo(2);
if (a === undefined) {
return b; // TypeScript infers b as number | undefined
}
return a; // TypeScript infers a as number (good!)
}
Because function foo returns either tuple (number, undefined) or (undefined, number), after not passing the a === undefined check, TypeScript is able to infer that the type of a is number when returning it.
And within the if block, because a is undefined we (humans) can infer the return type of foo here as [undefined, number] hence, type of b as number. However TypeScript doesn't seem intelligent enough to be able to tell this and reports that it's number | undefined.
Is there a workaround for narrowing down on union of tuples?
Update: The improved control-flow analysis in TypeScript 4.6 resolves the issue, so the fix below is no longer necessary. (See joematune's answer to this question.)
TypeScript's discriminating unions don't keep track of the dependency between a and b, so after you destructure the array, narrowing a won't affect the type of b. To still achieve the desired narrowing, you can directly test the array element, like this:
function bar() {
const arr = foo(2);
if (arr[0] === undefined) {
const b = arr[1]
return b; // TypeScript infers b as number (good!)
}
const a = arr[0]
return a; // TypeScript infers a as number (good!)
}
TypeScript playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With