When instantiating a mapped type, clone the type parameter. (#27597)

This gives the type parameter returned by getTypeParameterFromMappedType
an accurate constraint.

Fixes #27596.
This commit is contained in:
Matt McCutchen 2018-10-11 18:45:51 -04:00 committed by Wesley Wigham
parent 4d504f9b30
commit d19fb98ec6
5 changed files with 64 additions and 1 deletions

View File

@ -6850,7 +6850,7 @@ namespace ts {
function getConstraintTypeFromMappedType(type: MappedType) {
return type.constraintType ||
(type.constraintType = instantiateType(getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)), type.mapper || identityMapper) || errorType);
(type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType);
}
function getTemplateTypeFromMappedType(type: MappedType) {
@ -10413,6 +10413,12 @@ namespace ts {
const result = <AnonymousType>createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol);
if (type.objectFlags & ObjectFlags.Mapped) {
(<MappedType>result).declaration = (<MappedType>type).declaration;
// C.f. instantiateSignature
const origTypeParameter = getTypeParameterFromMappedType(<MappedType>type);
const freshTypeParameter = cloneTypeParameter(origTypeParameter);
(<MappedType>result).typeParameter = freshTypeParameter;
mapper = combineTypeMappers(makeUnaryTypeMapper(origTypeParameter, freshTypeParameter), mapper);
freshTypeParameter.mapper = mapper;
}
result.target = type;
result.mapper = mapper;

View File

@ -0,0 +1,14 @@
//// [mappedTypeParameterConstraint.ts]
// Repro for #27596
type MyMap<T> = {[P in keyof T]: T[keyof T]};
function foo<U>(arg: U): MyMap<U> {
return arg;
}
//// [mappedTypeParameterConstraint.js]
// Repro for #27596
function foo(arg) {
return arg;
}

View File

@ -0,0 +1,23 @@
=== tests/cases/compiler/mappedTypeParameterConstraint.ts ===
// Repro for #27596
type MyMap<T> = {[P in keyof T]: T[keyof T]};
>MyMap : Symbol(MyMap, Decl(mappedTypeParameterConstraint.ts, 0, 0))
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
>P : Symbol(P, Decl(mappedTypeParameterConstraint.ts, 2, 18))
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
>T : Symbol(T, Decl(mappedTypeParameterConstraint.ts, 2, 11))
function foo<U>(arg: U): MyMap<U> {
>foo : Symbol(foo, Decl(mappedTypeParameterConstraint.ts, 2, 45))
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
>arg : Symbol(arg, Decl(mappedTypeParameterConstraint.ts, 3, 16))
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
>MyMap : Symbol(MyMap, Decl(mappedTypeParameterConstraint.ts, 0, 0))
>U : Symbol(U, Decl(mappedTypeParameterConstraint.ts, 3, 13))
return arg;
>arg : Symbol(arg, Decl(mappedTypeParameterConstraint.ts, 3, 16))
}

View File

@ -0,0 +1,14 @@
=== tests/cases/compiler/mappedTypeParameterConstraint.ts ===
// Repro for #27596
type MyMap<T> = {[P in keyof T]: T[keyof T]};
>MyMap : MyMap<T>
function foo<U>(arg: U): MyMap<U> {
>foo : <U>(arg: U) => MyMap<U>
>arg : U
return arg;
>arg : U
}

View File

@ -0,0 +1,6 @@
// Repro for #27596
type MyMap<T> = {[P in keyof T]: T[keyof T]};
function foo<U>(arg: U): MyMap<U> {
return arg;
}