Reputation: 67
I want to do type narrowing when working with array types but union members aren't getting distinguished. It is weird that they work in the first function print1()
which is without arrays but doesn't work in the second function print2()
.
type Point = {
x: number;
y:number;
}
type Pair = [number, number]
type Coords = Point | Pair
function print1(a: Coords): number{
if("x" in a){
return a.x;
} else{
return a[0];
}
}
function print2(a: Pair[] | Point[]): void{
if("x" in a[0]){
console.log(a[0].x)
} else{
console.log(a[0][0])
}
}
Upvotes: 2
Views: 953
Reputation: 8718
It's interesting that it successfully narrows a[0]
but not a[1]
or the whole array, even though narrowing a[0]
can also narrow the rest of the array. You could consider reporting it if nobody hasn't already.
Until then, you can "fix" this with a simple type guard/predicate:
const isPairArray = (arr: Pair[] | Point[]): arr is Pair[] => arr[0] && 'x' in arr[0];
function print2(a: Pair[] | Point[]): void {
if (isPairArray(a)) {
console.log(a[0][0])
} else {
console.log(a[0].x)
}
}
In that case, a
is properly narrowed to either Pair[]
or Point[]
.
Upvotes: 3
Reputation: 6872
This is a "limitation" with TypeScript (its actually a great feature of typescript, since JavaScript is the real culprit here). According to typescript a[0]
in the expression 'x' in a[0]
might not reference the same value as a[0]
in the log statement console.log(a[0].x)
.
In this case, storing a[0]
in a variable will solve the issue.
function print2(a: Pair[] | Point[]): void{
const b = a[0];
if("x" in b){
console.log(b.x)
} else{
console.log(b[0])
}
}
Upvotes: 2