From eee211a2a6b73029554880fc917b402c09ee58c1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 6 Nov 2015 08:54:22 -0800 Subject: [PATCH] Instantiate type parameter constraints with type parameter as 'this' --- src/compiler/checker.ts | 24 +++++++++++++++++------- src/compiler/types.ts | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d836ce38d4..8161ead7c78 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2990,7 +2990,7 @@ namespace ts { (type).typeArguments = type.typeParameters; type.thisType = createType(TypeFlags.TypeParameter | TypeFlags.ThisType); type.thisType.symbol = symbol; - type.thisType.constraint = getTypeWithThisArgument(type); + type.thisType.constraint = type; } } return links.declaredType; @@ -3533,6 +3533,21 @@ namespace ts { return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type); } + /** + * The apparent type of a type parameter is the base constraint instantiated with the type parameter + * as the type argument for the 'this' type. + */ + function getApparentTypeOfTypeParameter(type: TypeParameter) { + if (!type.resolvedApparentType) { + let constraintType = getConstraintOfTypeParameter(type); + while (constraintType && constraintType.flags & TypeFlags.TypeParameter) { + constraintType = getConstraintOfTypeParameter(constraintType); + } + type.resolvedApparentType = getTypeWithThisArgument(constraintType || emptyObjectType, type); + } + return type.resolvedApparentType; + } + /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the @@ -3540,12 +3555,7 @@ namespace ts { */ function getApparentType(type: Type): Type { if (type.flags & TypeFlags.TypeParameter) { - do { - type = getConstraintOfTypeParameter(type); - } while (type && type.flags & TypeFlags.TypeParameter); - if (!type) { - type = emptyObjectType; - } + type = getApparentTypeOfTypeParameter(type); } if (type.flags & TypeFlags.StringLike) { type = globalStringType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f536a1e4693..679957d1d38 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1956,6 +1956,8 @@ namespace ts { target?: TypeParameter; // Instantiation target /* @internal */ mapper?: TypeMapper; // Instantiation mapper + /* @internal */ + resolvedApparentType: Type; } export const enum SignatureKind {