admin管理员组

文章数量:1389856

This code fails with the error in the title:

type Foo = {
    foo: number
    items: Foo[]
}
type Bar = {
    bar: number
    items: Foo[]
}

function func(list: Bar[], indices: number[]) {
    let cur: Foo[] | Bar[] = list
    for (const index of indices) {
        const item = cur[index] // error here
        cur = item.items
    }
}

Why is this happening? cur has an explicitly defined type. So does index. It appears that flow analysis determined that cur is actually Bar[] and errors out when I assign anything else to it?

If I change the definition of cur to let cur = list as Foo[] | Bar[] then there is no error, because it never changes to a different type. But this doesn't look good since the as statement might obscure errors if definitions change later on.

This code fails with the error in the title:

type Foo = {
    foo: number
    items: Foo[]
}
type Bar = {
    bar: number
    items: Foo[]
}

function func(list: Bar[], indices: number[]) {
    let cur: Foo[] | Bar[] = list
    for (const index of indices) {
        const item = cur[index] // error here
        cur = item.items
    }
}

Why is this happening? cur has an explicitly defined type. So does index. It appears that flow analysis determined that cur is actually Bar[] and errors out when I assign anything else to it?

If I change the definition of cur to let cur = list as Foo[] | Bar[] then there is no error, because it never changes to a different type. But this doesn't look good since the as statement might obscure errors if definitions change later on.

Share Improve this question edited Mar 15 at 19:00 riv asked Mar 15 at 18:27 rivriv 7,3633 gold badges41 silver badges74 bronze badges 1
  • TS detects a circularity, because the type of item depends on cur and the type of cur depends on item due to control flow analysis. A human being can analyze the types in a way that avoids this circularity, but TS has an inference algorithm and can't arbitrarily deviate from it. See ms/TS#45213. You can sidestep the problem by annotating (not using as) item (const item: Foo | Bar = ). Does this fully address the question? If so I'll write an answer or find a duplicate. If not, what am I missing? – jcalz Commented Mar 15 at 21:59
Add a comment  | 

1 Answer 1

Reset to default 1

The problem with the dynamic type change by cur = item.items. I suggest to narrow the type to the common items prop:

Playground

type Foo = {
    foo: number
    items: Foo[]
}
type Bar = {
    bar: number
    items: Foo[]
}

function func(list: Bar[], indices: number[]) {
    let cur: {items: Foo[]}[] = list;
    for (const index of indices) {
        const item = cur[index] // error here
        cur = item.items
    }
}

You could also do:

let cur: Pick<Foo, 'items'>[] = list;

本文标签: