Skip to content

Commit 735a67a

Browse files
authored
Fix iterable contextual type (#40592)
1 parent d779a19 commit 735a67a

File tree

5 files changed

+105
-1
lines changed

5 files changed

+105
-1
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23651,7 +23651,10 @@ namespace ts {
2365123651
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
2365223652
return arrayContextualType && (
2365323653
getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String)
23654-
|| getIteratedTypeOrElementType(IterationUse.Element, arrayContextualType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false));
23654+
|| mapType(
23655+
arrayContextualType,
23656+
t => getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false),
23657+
/*noReductions*/ true));
2365523658
}
2365623659

2365723660
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [contextualTypeIterableUnions.ts]
2+
declare class DMap<K, V> {
3+
constructor(iterable: Iterable<[K, V]> | undefined);
4+
}
5+
new DMap([["1", 2]]);
6+
7+
const i1: Iterable<{ a: true }> | undefined = [{ a: true }];
8+
const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }];
9+
const i3: Iterable<number> | 1[] = [2];
10+
11+
12+
//// [contextualTypeIterableUnions.js]
13+
"use strict";
14+
new DMap([["1", 2]]);
15+
const i1 = [{ a: true }];
16+
const i2 = [{ b: false }];
17+
const i3 = [2];
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/contextualTypeIterableUnions.ts ===
2+
declare class DMap<K, V> {
3+
>DMap : Symbol(DMap, Decl(contextualTypeIterableUnions.ts, 0, 0))
4+
>K : Symbol(K, Decl(contextualTypeIterableUnions.ts, 0, 19))
5+
>V : Symbol(V, Decl(contextualTypeIterableUnions.ts, 0, 21))
6+
7+
constructor(iterable: Iterable<[K, V]> | undefined);
8+
>iterable : Symbol(iterable, Decl(contextualTypeIterableUnions.ts, 1, 14))
9+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
10+
>K : Symbol(K, Decl(contextualTypeIterableUnions.ts, 0, 19))
11+
>V : Symbol(V, Decl(contextualTypeIterableUnions.ts, 0, 21))
12+
}
13+
new DMap([["1", 2]]);
14+
>DMap : Symbol(DMap, Decl(contextualTypeIterableUnions.ts, 0, 0))
15+
16+
const i1: Iterable<{ a: true }> | undefined = [{ a: true }];
17+
>i1 : Symbol(i1, Decl(contextualTypeIterableUnions.ts, 5, 5))
18+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
19+
>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 5, 20))
20+
>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 5, 48))
21+
22+
const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }];
23+
>i2 : Symbol(i2, Decl(contextualTypeIterableUnions.ts, 6, 5))
24+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
25+
>a : Symbol(a, Decl(contextualTypeIterableUnions.ts, 6, 20))
26+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
27+
>b : Symbol(b, Decl(contextualTypeIterableUnions.ts, 6, 44))
28+
>b : Symbol(b, Decl(contextualTypeIterableUnions.ts, 6, 61))
29+
30+
const i3: Iterable<number> | 1[] = [2];
31+
>i3 : Symbol(i3, Decl(contextualTypeIterableUnions.ts, 7, 5))
32+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
33+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/compiler/contextualTypeIterableUnions.ts ===
2+
declare class DMap<K, V> {
3+
>DMap : DMap<K, V>
4+
5+
constructor(iterable: Iterable<[K, V]> | undefined);
6+
>iterable : Iterable<[K, V]> | undefined
7+
}
8+
new DMap([["1", 2]]);
9+
>new DMap([["1", 2]]) : DMap<string, number>
10+
>DMap : typeof DMap
11+
>[["1", 2]] : [string, number][]
12+
>["1", 2] : [string, number]
13+
>"1" : "1"
14+
>2 : 2
15+
16+
const i1: Iterable<{ a: true }> | undefined = [{ a: true }];
17+
>i1 : Iterable<{ a: true; }> | undefined
18+
>a : true
19+
>true : true
20+
>[{ a: true }] : { a: true; }[]
21+
>{ a: true } : { a: true; }
22+
>a : true
23+
>true : true
24+
25+
const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }];
26+
>i2 : Iterable<{ a: true; }> | Iterable<{ b: false; }>
27+
>a : true
28+
>true : true
29+
>b : false
30+
>false : false
31+
>[{ b: false }] : { b: false; }[]
32+
>{ b: false } : { b: false; }
33+
>b : false
34+
>false : false
35+
36+
const i3: Iterable<number> | 1[] = [2];
37+
>i3 : Iterable<number> | 1[]
38+
>[2] : 2[]
39+
>2 : 2
40+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @strict: true
2+
// @target: esnext
3+
4+
declare class DMap<K, V> {
5+
constructor(iterable: Iterable<[K, V]> | undefined);
6+
}
7+
new DMap([["1", 2]]);
8+
9+
const i1: Iterable<{ a: true }> | undefined = [{ a: true }];
10+
const i2: Iterable<{ a: true }> | Iterable<{ b: false }> = [{ b: false }];
11+
const i3: Iterable<number> | 1[] = [2];

0 commit comments

Comments
 (0)