Skip to content

Commit 60f6ad3

Browse files
committed
When instantiating a mapped type, clone the type parameter.
This gives the type parameter returned by getTypeParameterFromMappedType an accurate constraint. Fixes microsoft#27596.
1 parent 85a3475 commit 60f6ad3

File tree

5 files changed

+64
-1
lines changed

5 files changed

+64
-1
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6828,7 +6828,7 @@ namespace ts {
68286828

68296829
function getConstraintTypeFromMappedType(type: MappedType) {
68306830
return type.constraintType ||
6831-
(type.constraintType = instantiateType(getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)), type.mapper || identityMapper) || errorType);
6831+
(type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType);
68326832
}
68336833

68346834
function getTemplateTypeFromMappedType(type: MappedType) {
@@ -10381,6 +10381,12 @@ namespace ts {
1038110381
const result = <AnonymousType>createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol);
1038210382
if (type.objectFlags & ObjectFlags.Mapped) {
1038310383
(<MappedType>result).declaration = (<MappedType>type).declaration;
10384+
// C.f. instantiateSignature
10385+
const origTypeParameter = getTypeParameterFromMappedType(<MappedType>type);
10386+
const freshTypeParameter = cloneTypeParameter(origTypeParameter);
10387+
(<MappedType>result).typeParameter = freshTypeParameter;
10388+
mapper = combineTypeMappers(makeUnaryTypeMapper(origTypeParameter, freshTypeParameter), mapper);
10389+
freshTypeParameter.mapper = mapper;
1038410390
}
1038510391
result.target = type;
1038610392
result.mapper = mapper;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [mappedTypeParameterConstraint.ts]
2+
// Repro for #27596
3+
4+
type MyMap<T> = {[P in keyof T]: T[keyof T]};
5+
function foo<U>(arg: U): MyMap<U> {
6+
return arg;
7+
}
8+
9+
10+
//// [mappedTypeParameterConstraint.js]
11+
// Repro for #27596
12+
function foo(arg) {
13+
return arg;
14+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/mappedTypeParameterConstraint.ts ===
2+
// Repro for #27596
3+
4+
type MyMap<T> = {[P in keyof T]: T[keyof T]};
5+
>MyMap : Symbol(MyMap, Decl(mappedTypeParameterConstraint.ts, 0, 0))
6+
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
7+
>P : Symbol(P, Decl(mappedTypeParameterConstraint.ts, 2, 18))
8+
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
9+
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
10+
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
11+
12+
function foo<U>(arg: U): MyMap<U> {
13+
>foo : Symbol(foo, Decl(mappedTypeParameterConstraint.ts, 2, 45))
14+
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
15+
>arg : Symbol(arg, Decl(mappedTypeParameterConstraint.ts, 3, 16))
16+
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
17+
>MyMap : Symbol(MyMap, Decl(mappedTypeParameterConstraint.ts, 0, 0))
18+
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
19+
20+
return arg;
21+
>arg : Symbol(arg, Decl(mappedTypeParameterConstraint.ts, 3, 16))
22+
}
23+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/mappedTypeParameterConstraint.ts ===
2+
// Repro for #27596
3+
4+
type MyMap<T> = {[P in keyof T]: T[keyof T]};
5+
>MyMap : MyMap<T>
6+
7+
function foo<U>(arg: U): MyMap<U> {
8+
>foo : <U>(arg: U) => MyMap<U>
9+
>arg : U
10+
11+
return arg;
12+
>arg : U
13+
}
14+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Repro for #27596
2+
3+
type MyMap<T> = {[P in keyof T]: T[keyof T]};
4+
function foo<U>(arg: U): MyMap<U> {
5+
return arg;
6+
}

0 commit comments

Comments
 (0)