Skip to content

Incorrect element type for for..of when expression is a UnionType #12244

Description

@rbuckton

TypeScript Version: 2.2.0-dev.20161114

Code

// --target es5
interface A { x: 0; y: C[]; }
interface B { x: 1; y: CD[]; }
interface C { x: 2; }
interface D { x: 3; }
type AB = A | B;
type CD = C | D;
declare let x: AB, y: CD;
for (y of x.y);

Expected behavior:

This should not error, as the element type of x.y should be CD, since the type of x.y is C[] | CD[].

Actual behavior:

Reports the error:

error TS2322: Type 'string | C | D' is not assignable to type 'CD'.
  Type 'string' is not assignable to type 'CD'.

The reason for this behavior is due to two causes:

  1. We do not perform subtype reduction for alias types, as they could be recursive and subtype reduction can be expensive. As a result, we do not reduce x.y from C[] | D[] to CD[] prior to calling checkElementTypeOfArrayOrString
  2. In checkElementTypeOfArrayOrString we call getUnionType passing in a filtered set of types (which still contains the types C[] and CD[]), passing true to the subtypeReduction parameter. This results in us reducing C[] | CD[] to CD[]. Unfortunately, this results in a false positive for the hasStringConstituent check later in the function.

As a result, we accidentally introduce stringType as a constituent, resulting in a type of string | C | D.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions