Skip to content

Typescript incorrectly narrows types when indexing into a union of arrays #43667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Jaymoss520 opened this issue Apr 14, 2021 · 2 comments
Closed
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@Jaymoss520
Copy link

Jaymoss520 commented Apr 14, 2021

Bug Report

⏯ Playground Link

Playground link

πŸ’» Code

interface A {
    first: any;
    second: any;
}

interface B {
    second: any;
}

function func(array: A[] | B[]) {
    const item = array[0];
    // typescript assumes item is of type 'B'

    if ('first' in item) {
        // typescript thinks this is impossible
        return item.first;
    }
}

πŸ™ Actual behavior

Typescript assumes that item is of type B.

Furthermore, when I try to narrow the type to A in order to access item.first, I get an error that says:

Property 'first' does not exist on type 'never'.(2339)

πŸ™‚ Expected behavior

Typescript should infer that item is of type A | B, not B.

The error does not occur when A is not a supertype of B

Also, the error does not occur when array has type (A | B)[] instead of A[] | B[]. The problem is that sometimes the latter type is the implied by typescript when accessing the properties of union types. Consider the following example:

interface C {
    items: A[]
}

interface D {
    items: B[]
}

function bar (value: C | D) {
    const item = value.items[0];
    // typescript assumes item is of type 'B'

    if ('first' in item) {
        // typescript thinks this is impossible
        return item.first;
    }
}
@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Apr 19, 2021
@RyanCavanaugh
Copy link
Member

This is a widening, not a narrowing.

There isn't much we can do here; subtype reduction is necessary for many other things to work. You can declare A and B such that they are mutually exclusive if this is the case, otherwise a type assertion is appropriate here.

@Jaymoss520
Copy link
Author

Jaymoss520 commented Apr 21, 2021

I understand if it's a design limitation but I don't know what you mean by "This is a widening, not a narrowing." In the example I gave, typescript assumes that item is of type B, which would be a narrowing no? (since it's a strict subset of the types that are actually possible, i.e. A OR B).

Also, I'm curious, what "other things" would not work if typescript inferred that item had type A | B instead of B?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

2 participants