From 9e613b9fd54495bb5d980498c15fc83e2430b5e3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 3 Jun 2017 16:52:38 -0700 Subject: [PATCH] Preserve type parameters in generic contextual pure function types --- src/compiler/checker.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b2f34987a8d..5ad2ffeac6e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14959,11 +14959,21 @@ namespace ts { // We clone the contextual mapper to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const mapper = cloneTypeMapper(getContextualMapper(node)); - const instantiatedType = instantiateType(contextualType, mapper); - const returnType = getReturnTypeOfSignature(signature); - // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, instantiatedType, returnType, InferencePriority.ReturnType); + const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node))); + // If the contextual type is a generic pure function type, we instantiate the type with + // its own type parameters and type arguments. This ensures that the type parameters are + // not erased to type any during type inference such that they can be inferred as actual + // types from the contextual type. For example: + // declare function arrayMap(f: (x: T) => U): (a: T[]) => U[]; + // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); + // Above, the type of the 'value' parameter is inferred to be 'A'. + const contextualSignature = getSingleCallSignature(instantiatedType); + const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? + getOrCreateTypeFromSignature(getSignatureInstantiation(contextualSignature, contextualSignature.typeParameters)) : + instantiatedType; + const inferenceTargetType = getReturnTypeOfSignature(signature); + // Inferences made from return types have lower priority than all other inferences. + inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); } }