Here's an example (not a good one :p):
type RandomType = {x: number, y: number}
type UnifiedTypes = RandomType | 0
type ArrayOfTypes = Array<(RandomType | UnifiedTypes)[]>
const newIns: ArrayOfTypes = [[0, {x: 10, y: 201}], [0, {x: 10, y: 201}]]
for(let i=0; i < newIns.length; i){
for(let j=0; j < newIns[i].length; j){
if(newIns[i][j] !== 0){
newIns[i][j].x = 30 // Property 'x' does not exist on type 'UnifiedTypes'. Property 'x' does not exist on type '0'
}
}
}
// Hoewever, when outside of loop compiler runs fine
if(newIns[0][0] !== 0) {
newIns[0][0].x = 33; // no error thrown
}
Narrowing doesn't seem to work when looping through a union typed array so I'm bit lost. Did I miss smt?
By narrowing down which type the indexed element is going to hold, the typescript compiler should be able to figure out the type of the element array in the specified index and hence assignement occurs safely.
CodePudding user response:
In my opinion when you type of newIns[i][j]
is understood as RandomType | UnifiedTypes
at the point. But when you check newIns[i][j] !== 0
in the loop, the type of newIns[i][j]
is narrowed to UnifiedTypes
which is RandomType | 0
. But, when you check newIns[0][0] !== 0
, the type of newIns[0][0]
is narrowed to RandomType
, so the compiler knows that newIns[0][0]
has a property x
. In other words see below down example.
type Shape = 'circle' | 'square'
type Color = 'red' | 'blue'
type Item = Shape | Color
const items: Item[] = ['circle', 'blue', 'red']
for (let i = 0; i < items.length; i ) {
if (items[i] !== 'circle') {
console.log(items[i].length) // Property 'length' does not exist on type 'Item'.
}
}
As you're well aware items
refers to Item
type and items[i]
is inferred as Item
, which is Shape | Color
. But, when you check items[i] !== 'circle'
, you narrow the type of items[i]
to Color
, because you are excluding the possibility that it is 'circle'
from the union.
You could fix this like this.
console.log((items[i] as Color).length)
CodePudding user response:
This will work if you create a constant for the newIns[i][j]
element. For her, TS will be able to correctly process the type.
type RandomType = {x: number, y: number}
type UnifiedTypes = RandomType | 0
type ArrayOfTypes = Array<(RandomType | UnifiedTypes)[]>
const newIns: ArrayOfTypes = [[0, {x: 10, y: 201}], [0, {x: 10, y: 201}]]
for(let i=0; i < newIns.length; i){
for(let j=0; j < newIns[i].length; j){
const element = newIns[i][j]
if(element !== 0){
element.x = 30
}
}
}