Improve contextual typing by generic rest parameter

This commit is contained in:
Anders Hejlsberg 2019-02-19 07:02:37 -10:00
parent b2b360a64f
commit 451f65332c

View file

@ -10669,9 +10669,9 @@ namespace ts {
return !!(<InferenceContext>mapper).typeParameters;
}
function cloneTypeMapper(mapper: TypeMapper): TypeMapper {
function cloneTypeMapper(mapper: TypeMapper, extraFlags: InferenceFlags = 0): TypeMapper {
return mapper && isInferenceContext(mapper) ?
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) :
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | extraFlags, mapper.compareTypes, mapper.inferences) :
mapper;
}
@ -19984,7 +19984,7 @@ 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 instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node)));
const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node), InferenceFlags.NoDefault));
// If the contextual type is a generic function type with a single call signature, 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
@ -21652,6 +21652,17 @@ namespace ts {
}
}
}
const restType = getEffectiveRestType(context);
if (restType && restType.flags & TypeFlags.TypeParameter) {
// The contextual signature has a generic rest parameter. We first instantiate the contextual
// signature (without fixing type parameters) and assign types to contextually typed parameters.
const instantiatedContext = instantiateSignature(context, cloneTypeMapper(mapper));
assignContextualParameterTypes(signature, instantiatedContext);
// We then infer from a tuple type representing the parameters that correspond to the contextual
// rest parameter.
const restPos = getParameterCount(context) - 1;
inferTypes((<InferenceContext>mapper).inferences, getRestTypeAtPosition(signature, restPos), restType);
}
}
function assignContextualParameterTypes(signature: Signature, context: Signature) {