在联合类型数组上循环时,typescript编译器引发奇怪的错误

qnyhuwrf  于 2023-01-31  发布在  TypeScript
关注(0)|答案(2)|浏览(135)

下面是一个例子(不是一个好例子: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
}

当循环遍历一个联合类型的数组时,缩窄似乎不起作用,所以我有点迷惑。我错过了smt吗?
通过缩小索引元素要保存的类型,类型脚本编译器应该能够计算出指定索引中元素数组的类型,从而安全地进行赋值。

ia2d9nvy

ia2d9nvy1#

在我看来,当你输入newIns[i][j]时,在这一点上理解为RandomType | UnifiedTypes。但是当你在循环中检查newIns[i][j] !== 0时,newIns[i][j]的类型被缩小为UnifiedTypes,即RandomType | 0。但是,当你检查newIns[0][0] !== 0时,newIns[0][0]的类型被缩小为RandomType。所以编译器知道newIns[0][0]有一个属性x。换句话说,见下面的例子。

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'.
  }
}

如您所知,items引用Item类型,items[i]被推断为Item,即Shape | Color,但是,当您选中items[i] !== 'circle'时,您将items[i]的类型缩小为Color,因为您从联合中排除了它是'circle'的可能性。
你可以像这样解决。
x1米20英寸1x

wz3gfoph

wz3gfoph2#

如果你为newIns[i][j]元素创建一个常量的话,这将是有效的。对她来说,TS将能够正确地处理类型。

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
        }
    }
}

相关问题