Skip to content

Commit a5d9e96

Browse files
authored
Merge pull request #12301 from Microsoft/recursiveMappedTypes
Fix recursive mapped types
2 parents 3110f40 + 78726ae commit a5d9e96

File tree

5 files changed

+113
-0
lines changed

5 files changed

+113
-0
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4489,6 +4489,8 @@ namespace ts {
44894489
const members: SymbolTable = createMap<Symbol>();
44904490
let stringIndexInfo: IndexInfo;
44914491
let numberIndexInfo: IndexInfo;
4492+
// Resolve upfront such that recursive references see an empty object type.
4493+
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined);
44924494
// In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type,
44934495
// and T as the template type.
44944496
const typeParameter = getTypeParameterFromMappedType(type);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [recursiveMappedTypes.ts]
2+
3+
// Recursive mapped types simply appear empty
4+
5+
type Recurse = {
6+
[K in keyof Recurse]: Recurse[K]
7+
}
8+
9+
type Recurse1 = {
10+
[K in keyof Recurse2]: Recurse2[K]
11+
}
12+
13+
type Recurse2 = {
14+
[K in keyof Recurse1]: Recurse1[K]
15+
}
16+
17+
//// [recursiveMappedTypes.js]
18+
// Recursive mapped types simply appear empty
19+
20+
21+
//// [recursiveMappedTypes.d.ts]
22+
declare type Recurse = {
23+
[K in keyof Recurse]: Recurse[K];
24+
};
25+
declare type Recurse1 = {
26+
[K in keyof Recurse2]: Recurse2[K];
27+
};
28+
declare type Recurse2 = {
29+
[K in keyof Recurse1]: Recurse1[K];
30+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts ===
2+
3+
// Recursive mapped types simply appear empty
4+
5+
type Recurse = {
6+
>Recurse : Symbol(Recurse, Decl(recursiveMappedTypes.ts, 0, 0))
7+
8+
[K in keyof Recurse]: Recurse[K]
9+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 4, 5))
10+
>Recurse : Symbol(Recurse, Decl(recursiveMappedTypes.ts, 0, 0))
11+
>Recurse : Symbol(Recurse, Decl(recursiveMappedTypes.ts, 0, 0))
12+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 4, 5))
13+
}
14+
15+
type Recurse1 = {
16+
>Recurse1 : Symbol(Recurse1, Decl(recursiveMappedTypes.ts, 5, 1))
17+
18+
[K in keyof Recurse2]: Recurse2[K]
19+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 8, 5))
20+
>Recurse2 : Symbol(Recurse2, Decl(recursiveMappedTypes.ts, 9, 1))
21+
>Recurse2 : Symbol(Recurse2, Decl(recursiveMappedTypes.ts, 9, 1))
22+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 8, 5))
23+
}
24+
25+
type Recurse2 = {
26+
>Recurse2 : Symbol(Recurse2, Decl(recursiveMappedTypes.ts, 9, 1))
27+
28+
[K in keyof Recurse1]: Recurse1[K]
29+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 12, 5))
30+
>Recurse1 : Symbol(Recurse1, Decl(recursiveMappedTypes.ts, 5, 1))
31+
>Recurse1 : Symbol(Recurse1, Decl(recursiveMappedTypes.ts, 5, 1))
32+
>K : Symbol(K, Decl(recursiveMappedTypes.ts, 12, 5))
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts ===
2+
3+
// Recursive mapped types simply appear empty
4+
5+
type Recurse = {
6+
>Recurse : Recurse
7+
8+
[K in keyof Recurse]: Recurse[K]
9+
>K : K
10+
>Recurse : Recurse
11+
>Recurse : Recurse
12+
>K : K
13+
}
14+
15+
type Recurse1 = {
16+
>Recurse1 : Recurse1
17+
18+
[K in keyof Recurse2]: Recurse2[K]
19+
>K : K
20+
>Recurse2 : Recurse2
21+
>Recurse2 : Recurse2
22+
>K : K
23+
}
24+
25+
type Recurse2 = {
26+
>Recurse2 : Recurse2
27+
28+
[K in keyof Recurse1]: Recurse1[K]
29+
>K : K
30+
>Recurse1 : Recurse1
31+
>Recurse1 : Recurse1
32+
>K : K
33+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @declaration: true
2+
3+
// Recursive mapped types simply appear empty
4+
5+
type Recurse = {
6+
[K in keyof Recurse]: Recurse[K]
7+
}
8+
9+
type Recurse1 = {
10+
[K in keyof Recurse2]: Recurse2[K]
11+
}
12+
13+
type Recurse2 = {
14+
[K in keyof Recurse1]: Recurse1[K]
15+
}

0 commit comments

Comments
 (0)