Skip to content

Commit 48244d8

Browse files
authored
fix: [Symbol.iterator]() lost on union with never (#62661)
1 parent efca03f commit 48244d8

7 files changed

+539
-0
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45842,6 +45842,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4584245842
* the `[Symbol.asyncIterator]()` method first, and then the `[Symbol.iterator]()` method.
4584345843
*/
4584445844
function getIterationTypesOfIterable(type: Type, use: IterationUse, errorNode: Node | undefined) {
45845+
type = getReducedType(type);
4584545846
if (type === silentNeverType) {
4584645847
return silentNeverIterationTypes;
4584745848
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//// [tests/cases/compiler/iterableWithNeverAsUnionMember.ts] ////
2+
3+
=== iterableWithNeverAsUnionMember.ts ===
4+
declare const o1: { a: "foo" } & { a: "bar" };
5+
>o1 : Symbol(o1, Decl(iterableWithNeverAsUnionMember.ts, 0, 13))
6+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 0, 19))
7+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 0, 34))
8+
9+
const [el1] = o1; // error
10+
>el1 : Symbol(el1, Decl(iterableWithNeverAsUnionMember.ts, 1, 7))
11+
>o1 : Symbol(o1, Decl(iterableWithNeverAsUnionMember.ts, 0, 13))
12+
13+
// https://github.com/microsoft/TypeScript/issues/62462
14+
declare var x: number[] | ({ t: "a" } & { t: "b" });
15+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
16+
>t : Symbol(t, Decl(iterableWithNeverAsUnionMember.ts, 4, 28))
17+
>t : Symbol(t, Decl(iterableWithNeverAsUnionMember.ts, 4, 41))
18+
19+
let [el2] = x; // ok
20+
>el2 : Symbol(el2, Decl(iterableWithNeverAsUnionMember.ts, 5, 5))
21+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
22+
23+
for (const elem of x) { // ok
24+
>elem : Symbol(elem, Decl(iterableWithNeverAsUnionMember.ts, 7, 10))
25+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
26+
27+
elem.toFixed();
28+
>elem.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
29+
>elem : Symbol(elem, Decl(iterableWithNeverAsUnionMember.ts, 7, 10))
30+
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
31+
}
32+
33+
type Shape =
34+
>Shape : Symbol(Shape, Decl(iterableWithNeverAsUnionMember.ts, 9, 1))
35+
36+
| { kind: "circle"; radius: number }
37+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 12, 5))
38+
>radius : Symbol(radius, Decl(iterableWithNeverAsUnionMember.ts, 12, 21))
39+
40+
| { kind: "rectangle"; width: number; height: number };
41+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 13, 5))
42+
>width : Symbol(width, Decl(iterableWithNeverAsUnionMember.ts, 13, 24))
43+
>height : Symbol(height, Decl(iterableWithNeverAsUnionMember.ts, 13, 39))
44+
45+
type Circle = Shape & { kind: "circle" };
46+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
47+
>Shape : Symbol(Shape, Decl(iterableWithNeverAsUnionMember.ts, 9, 1))
48+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 15, 23))
49+
50+
function doStuffWithCircle(arg: Circle | [Circle, (newValue: Circle) => void]) {
51+
>doStuffWithCircle : Symbol(doStuffWithCircle, Decl(iterableWithNeverAsUnionMember.ts, 15, 41))
52+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
53+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
54+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
55+
>newValue : Symbol(newValue, Decl(iterableWithNeverAsUnionMember.ts, 17, 51))
56+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
57+
58+
if (Array.isArray(arg)) {
59+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
60+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
61+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
62+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
63+
64+
let [value, setValue] = arg; // ok
65+
>value : Symbol(value, Decl(iterableWithNeverAsUnionMember.ts, 19, 9))
66+
>setValue : Symbol(setValue, Decl(iterableWithNeverAsUnionMember.ts, 19, 15))
67+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
68+
}
69+
}
70+
71+
function f1<T extends { a: "foo" } & { a: "bar" }>(x: T) {
72+
>f1 : Symbol(f1, Decl(iterableWithNeverAsUnionMember.ts, 21, 1))
73+
>T : Symbol(T, Decl(iterableWithNeverAsUnionMember.ts, 23, 12))
74+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 23, 23))
75+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 23, 38))
76+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 23, 51))
77+
>T : Symbol(T, Decl(iterableWithNeverAsUnionMember.ts, 23, 12))
78+
79+
let [y] = x; // error
80+
>y : Symbol(y, Decl(iterableWithNeverAsUnionMember.ts, 24, 7))
81+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 23, 51))
82+
}
83+
84+
declare const o2: ({ a: "foo" } & { a: "bar" }) | ({ b: "qwe" } & { b: "rty" });
85+
>o2 : Symbol(o2, Decl(iterableWithNeverAsUnionMember.ts, 27, 13))
86+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 27, 20))
87+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 27, 35))
88+
>b : Symbol(b, Decl(iterableWithNeverAsUnionMember.ts, 27, 52))
89+
>b : Symbol(b, Decl(iterableWithNeverAsUnionMember.ts, 27, 67))
90+
91+
const [el3] = o2; // error
92+
>el3 : Symbol(el3, Decl(iterableWithNeverAsUnionMember.ts, 28, 7))
93+
>o2 : Symbol(o2, Decl(iterableWithNeverAsUnionMember.ts, 27, 13))
94+
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//// [tests/cases/compiler/iterableWithNeverAsUnionMember.ts] ////
2+
3+
=== iterableWithNeverAsUnionMember.ts ===
4+
declare const o1: { a: "foo" } & { a: "bar" };
5+
>o1 : never
6+
> : ^^^^^
7+
>a : "foo"
8+
> : ^^^^^
9+
>a : "bar"
10+
> : ^^^^^
11+
12+
const [el1] = o1; // error
13+
>el1 : never
14+
> : ^^^^^
15+
>o1 : never
16+
> : ^^^^^
17+
18+
// https://github.com/microsoft/TypeScript/issues/62462
19+
declare var x: number[] | ({ t: "a" } & { t: "b" });
20+
>x : number[]
21+
> : ^^^^^^^^
22+
>t : "a"
23+
> : ^^^
24+
>t : "b"
25+
> : ^^^
26+
27+
let [el2] = x; // ok
28+
>el2 : number
29+
> : ^^^^^^
30+
>x : number[]
31+
> : ^^^^^^^^
32+
33+
for (const elem of x) { // ok
34+
>elem : number
35+
> : ^^^^^^
36+
>x : number[]
37+
> : ^^^^^^^^
38+
39+
elem.toFixed();
40+
>elem.toFixed() : string
41+
> : ^^^^^^
42+
>elem.toFixed : (fractionDigits?: number) => string
43+
> : ^ ^^^ ^^^^^
44+
>elem : number
45+
> : ^^^^^^
46+
>toFixed : (fractionDigits?: number) => string
47+
> : ^ ^^^ ^^^^^
48+
}
49+
50+
type Shape =
51+
>Shape : Shape
52+
> : ^^^^^
53+
54+
| { kind: "circle"; radius: number }
55+
>kind : "circle"
56+
> : ^^^^^^^^
57+
>radius : number
58+
> : ^^^^^^
59+
60+
| { kind: "rectangle"; width: number; height: number };
61+
>kind : "rectangle"
62+
> : ^^^^^^^^^^^
63+
>width : number
64+
> : ^^^^^^
65+
>height : number
66+
> : ^^^^^^
67+
68+
type Circle = Shape & { kind: "circle" };
69+
>Circle : { kind: "circle"; radius: number; } & { kind: "circle"; }
70+
> : ^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^
71+
>kind : "circle"
72+
> : ^^^^^^^^
73+
74+
function doStuffWithCircle(arg: Circle | [Circle, (newValue: Circle) => void]) {
75+
>doStuffWithCircle : (arg: Circle | [Circle, (newValue: Circle) => void]) => void
76+
> : ^ ^^ ^^^^^^^^^
77+
>arg : ({ kind: "circle"; radius: number; } & { kind: "circle"; }) | [{ kind: "circle"; radius: number; } & { kind: "circle"; }, (newValue: Circle) => void]
78+
> : ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^ ^^ ^^^^^ ^
79+
>newValue : { kind: "circle"; radius: number; } & { kind: "circle"; }
80+
> : ^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^
81+
82+
if (Array.isArray(arg)) {
83+
>Array.isArray(arg) : boolean
84+
> : ^^^^^^^
85+
>Array.isArray : (arg: any) => arg is any[]
86+
> : ^ ^^ ^^^^^
87+
>Array : ArrayConstructor
88+
> : ^^^^^^^^^^^^^^^^
89+
>isArray : (arg: any) => arg is any[]
90+
> : ^ ^^ ^^^^^
91+
>arg : ({ kind: "circle"; radius: number; } & { kind: "circle"; }) | [{ kind: "circle"; radius: number; } & { kind: "circle"; }, (newValue: Circle) => void]
92+
> : ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^ ^^ ^^^^^ ^
93+
94+
let [value, setValue] = arg; // ok
95+
>value : { kind: "circle"; radius: number; } & { kind: "circle"; }
96+
> : ^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^
97+
>setValue : (newValue: Circle) => void
98+
> : ^ ^^ ^^^^^
99+
>arg : [{ kind: "circle"; radius: number; } & { kind: "circle"; }, (newValue: Circle) => void]
100+
> : ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^ ^^ ^^^^^ ^
101+
}
102+
}
103+
104+
function f1<T extends { a: "foo" } & { a: "bar" }>(x: T) {
105+
>f1 : <T extends { a: "foo"; } & { a: "bar"; }>(x: T) => void
106+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^
107+
>a : "foo"
108+
> : ^^^^^
109+
>a : "bar"
110+
> : ^^^^^
111+
>x : T
112+
> : ^
113+
114+
let [y] = x; // error
115+
>y : never
116+
> : ^^^^^
117+
>x : T
118+
> : ^
119+
}
120+
121+
declare const o2: ({ a: "foo" } & { a: "bar" }) | ({ b: "qwe" } & { b: "rty" });
122+
>o2 : never
123+
> : ^^^^^
124+
>a : "foo"
125+
> : ^^^^^
126+
>a : "bar"
127+
> : ^^^^^
128+
>b : "qwe"
129+
> : ^^^^^
130+
>b : "rty"
131+
> : ^^^^^
132+
133+
const [el3] = o2; // error
134+
>el3 : never
135+
> : ^^^^^
136+
>o2 : never
137+
> : ^^^^^
138+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
iterableWithNeverAsUnionMember.ts(2,7): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
2+
iterableWithNeverAsUnionMember.ts(25,7): error TS2488: Type 'T' must have a '[Symbol.iterator]()' method that returns an iterator.
3+
iterableWithNeverAsUnionMember.ts(29,7): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
4+
5+
6+
==== iterableWithNeverAsUnionMember.ts (3 errors) ====
7+
declare const o1: { a: "foo" } & { a: "bar" };
8+
const [el1] = o1; // error
9+
~~~~~
10+
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
11+
12+
// https://github.com/microsoft/TypeScript/issues/62462
13+
declare var x: number[] | ({ t: "a" } & { t: "b" });
14+
let [el2] = x; // ok
15+
16+
for (const elem of x) { // ok
17+
elem.toFixed();
18+
}
19+
20+
type Shape =
21+
| { kind: "circle"; radius: number }
22+
| { kind: "rectangle"; width: number; height: number };
23+
24+
type Circle = Shape & { kind: "circle" };
25+
26+
function doStuffWithCircle(arg: Circle | [Circle, (newValue: Circle) => void]) {
27+
if (Array.isArray(arg)) {
28+
let [value, setValue] = arg; // ok
29+
}
30+
}
31+
32+
function f1<T extends { a: "foo" } & { a: "bar" }>(x: T) {
33+
let [y] = x; // error
34+
~~~
35+
!!! error TS2488: Type 'T' must have a '[Symbol.iterator]()' method that returns an iterator.
36+
}
37+
38+
declare const o2: ({ a: "foo" } & { a: "bar" }) | ({ b: "qwe" } & { b: "rty" });
39+
const [el3] = o2; // error
40+
~~~~~
41+
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//// [tests/cases/compiler/iterableWithNeverAsUnionMember.ts] ////
2+
3+
=== iterableWithNeverAsUnionMember.ts ===
4+
declare const o1: { a: "foo" } & { a: "bar" };
5+
>o1 : Symbol(o1, Decl(iterableWithNeverAsUnionMember.ts, 0, 13))
6+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 0, 19))
7+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 0, 34))
8+
9+
const [el1] = o1; // error
10+
>el1 : Symbol(el1, Decl(iterableWithNeverAsUnionMember.ts, 1, 7))
11+
>o1 : Symbol(o1, Decl(iterableWithNeverAsUnionMember.ts, 0, 13))
12+
13+
// https://github.com/microsoft/TypeScript/issues/62462
14+
declare var x: number[] | ({ t: "a" } & { t: "b" });
15+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
16+
>t : Symbol(t, Decl(iterableWithNeverAsUnionMember.ts, 4, 28))
17+
>t : Symbol(t, Decl(iterableWithNeverAsUnionMember.ts, 4, 41))
18+
19+
let [el2] = x; // ok
20+
>el2 : Symbol(el2, Decl(iterableWithNeverAsUnionMember.ts, 5, 5))
21+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
22+
23+
for (const elem of x) { // ok
24+
>elem : Symbol(elem, Decl(iterableWithNeverAsUnionMember.ts, 7, 10))
25+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 4, 11))
26+
27+
elem.toFixed();
28+
>elem.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
29+
>elem : Symbol(elem, Decl(iterableWithNeverAsUnionMember.ts, 7, 10))
30+
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
31+
}
32+
33+
type Shape =
34+
>Shape : Symbol(Shape, Decl(iterableWithNeverAsUnionMember.ts, 9, 1))
35+
36+
| { kind: "circle"; radius: number }
37+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 12, 5))
38+
>radius : Symbol(radius, Decl(iterableWithNeverAsUnionMember.ts, 12, 21))
39+
40+
| { kind: "rectangle"; width: number; height: number };
41+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 13, 5))
42+
>width : Symbol(width, Decl(iterableWithNeverAsUnionMember.ts, 13, 24))
43+
>height : Symbol(height, Decl(iterableWithNeverAsUnionMember.ts, 13, 39))
44+
45+
type Circle = Shape & { kind: "circle" };
46+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
47+
>Shape : Symbol(Shape, Decl(iterableWithNeverAsUnionMember.ts, 9, 1))
48+
>kind : Symbol(kind, Decl(iterableWithNeverAsUnionMember.ts, 15, 23))
49+
50+
function doStuffWithCircle(arg: Circle | [Circle, (newValue: Circle) => void]) {
51+
>doStuffWithCircle : Symbol(doStuffWithCircle, Decl(iterableWithNeverAsUnionMember.ts, 15, 41))
52+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
53+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
54+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
55+
>newValue : Symbol(newValue, Decl(iterableWithNeverAsUnionMember.ts, 17, 51))
56+
>Circle : Symbol(Circle, Decl(iterableWithNeverAsUnionMember.ts, 13, 57))
57+
58+
if (Array.isArray(arg)) {
59+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
60+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
61+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
62+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
63+
64+
let [value, setValue] = arg; // ok
65+
>value : Symbol(value, Decl(iterableWithNeverAsUnionMember.ts, 19, 9))
66+
>setValue : Symbol(setValue, Decl(iterableWithNeverAsUnionMember.ts, 19, 15))
67+
>arg : Symbol(arg, Decl(iterableWithNeverAsUnionMember.ts, 17, 27))
68+
}
69+
}
70+
71+
function f1<T extends { a: "foo" } & { a: "bar" }>(x: T) {
72+
>f1 : Symbol(f1, Decl(iterableWithNeverAsUnionMember.ts, 21, 1))
73+
>T : Symbol(T, Decl(iterableWithNeverAsUnionMember.ts, 23, 12))
74+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 23, 23))
75+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 23, 38))
76+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 23, 51))
77+
>T : Symbol(T, Decl(iterableWithNeverAsUnionMember.ts, 23, 12))
78+
79+
let [y] = x; // error
80+
>y : Symbol(y, Decl(iterableWithNeverAsUnionMember.ts, 24, 7))
81+
>x : Symbol(x, Decl(iterableWithNeverAsUnionMember.ts, 23, 51))
82+
}
83+
84+
declare const o2: ({ a: "foo" } & { a: "bar" }) | ({ b: "qwe" } & { b: "rty" });
85+
>o2 : Symbol(o2, Decl(iterableWithNeverAsUnionMember.ts, 27, 13))
86+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 27, 20))
87+
>a : Symbol(a, Decl(iterableWithNeverAsUnionMember.ts, 27, 35))
88+
>b : Symbol(b, Decl(iterableWithNeverAsUnionMember.ts, 27, 52))
89+
>b : Symbol(b, Decl(iterableWithNeverAsUnionMember.ts, 27, 67))
90+
91+
const [el3] = o2; // error
92+
>el3 : Symbol(el3, Decl(iterableWithNeverAsUnionMember.ts, 28, 7))
93+
>o2 : Symbol(o2, Decl(iterableWithNeverAsUnionMember.ts, 27, 13))
94+

0 commit comments

Comments
 (0)