Skip to content

Commit f667b5c

Browse files
authored
Merge pull request #13366 from Microsoft/fixMappedTypeCombinedMappers
Fix bug in recursive mapped type instantiation
2 parents ecb2115 + 3bc8c7e commit f667b5c

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6558,6 +6558,12 @@ namespace ts {
65586558
return mapper;
65596559
}
65606560

6561+
function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper) {
6562+
const mapper: TypeMapper = t => t === source ? target : baseMapper(t);
6563+
mapper.mappedTypes = baseMapper.mappedTypes;
6564+
return mapper;
6565+
}
6566+
65616567
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
65626568
const result = <TypeParameter>createType(TypeFlags.TypeParameter);
65636569
result.symbol = typeParameter.symbol;
@@ -6656,10 +6662,7 @@ namespace ts {
66566662
if (typeVariable !== mappedTypeVariable) {
66576663
return mapType(mappedTypeVariable, t => {
66586664
if (isMappableType(t)) {
6659-
const replacementMapper = createTypeMapper([typeVariable], [t]);
6660-
const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper);
6661-
combinedMapper.mappedTypes = mapper.mappedTypes;
6662-
return instantiateMappedObjectType(type, combinedMapper);
6665+
return instantiateMappedObjectType(type, createReplacementMapper(typeVariable, t, mapper));
66636666
}
66646667
return t;
66656668
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
tests/cases/compiler/mappedTypeWithCombinedTypeMappers.ts(18,7): error TS2322: Type 'string' is not assignable to type '{ important: boolean; }'.
2+
3+
4+
==== tests/cases/compiler/mappedTypeWithCombinedTypeMappers.ts (1 errors) ====
5+
// Repro from #13351
6+
7+
type Meta<T, A> = {
8+
readonly[P in keyof T]: {
9+
value: T[P];
10+
also: A;
11+
readonly children: Meta<T[P], A>;
12+
};
13+
}
14+
15+
interface Input {
16+
x: string;
17+
y: number;
18+
}
19+
20+
declare const output: Meta<Input, boolean>;
21+
22+
const shouldFail: { important: boolean } = output.x.children;
23+
~~~~~~~~~~
24+
!!! error TS2322: Type 'string' is not assignable to type '{ important: boolean; }'.
25+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [mappedTypeWithCombinedTypeMappers.ts]
2+
// Repro from #13351
3+
4+
type Meta<T, A> = {
5+
readonly[P in keyof T]: {
6+
value: T[P];
7+
also: A;
8+
readonly children: Meta<T[P], A>;
9+
};
10+
}
11+
12+
interface Input {
13+
x: string;
14+
y: number;
15+
}
16+
17+
declare const output: Meta<Input, boolean>;
18+
19+
const shouldFail: { important: boolean } = output.x.children;
20+
21+
22+
//// [mappedTypeWithCombinedTypeMappers.js]
23+
// Repro from #13351
24+
var shouldFail = output.x.children;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Repro from #13351
2+
3+
type Meta<T, A> = {
4+
readonly[P in keyof T]: {
5+
value: T[P];
6+
also: A;
7+
readonly children: Meta<T[P], A>;
8+
};
9+
}
10+
11+
interface Input {
12+
x: string;
13+
y: number;
14+
}
15+
16+
declare const output: Meta<Input, boolean>;
17+
18+
const shouldFail: { important: boolean } = output.x.children;

0 commit comments

Comments
 (0)