@@ -14636,18 +14636,18 @@ namespace ts {
14636
14636
}
14637
14637
14638
14638
function inferFromProperties(source: Type, target: Type) {
14639
- if (isTupleType(source)) {
14639
+ if (isArrayType(source) || isTupleType(source)) {
14640
14640
if (isTupleType(target)) {
14641
- const sourceLength = getLengthOfTupleType(source);
14641
+ const sourceLength = isTupleType(source) ? getLengthOfTupleType(source) : 0 ;
14642
14642
const targetLength = getLengthOfTupleType(target);
14643
- const sourceRestType = getRestTypeOfTupleType(source);
14643
+ const sourceRestType = isTupleType(source) ? getRestTypeOfTupleType(source) : getElementTypeOfArrayType (source);
14644
14644
const targetRestType = getRestTypeOfTupleType(target);
14645
14645
const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength;
14646
14646
for (let i = 0; i < fixedLength; i++) {
14647
- inferFromTypes(i < sourceLength ? source.typeArguments![i] : sourceRestType!, target.typeArguments![i]);
14647
+ inferFromTypes(i < sourceLength ? (<TypeReference> source) .typeArguments![i] : sourceRestType!, target.typeArguments![i]);
14648
14648
}
14649
14649
if (targetRestType) {
14650
- const types = fixedLength < sourceLength ? source.typeArguments!.slice(fixedLength, sourceLength) : [];
14650
+ const types = fixedLength < sourceLength ? (<TypeReference> source) .typeArguments!.slice(fixedLength, sourceLength) : [];
14651
14651
if (sourceRestType) {
14652
14652
types.push(sourceRestType);
14653
14653
}
@@ -17759,19 +17759,49 @@ namespace ts {
17759
17759
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
17760
17760
// be "pushed" onto a node using the contextualType property.
17761
17761
function getApparentTypeOfContextualType(node: Expression): Type | undefined {
17762
- let contextualType = getContextualType(node);
17763
- contextualType = contextualType && mapType(contextualType, getApparentType);
17764
- if (contextualType && contextualType.flags & TypeFlags.Union) {
17765
- if (isObjectLiteralExpression(node)) {
17766
- return discriminateContextualTypeByObjectMembers(node, contextualType as UnionType);
17762
+ const contextualType = instantiateContextualType(getContextualType(node), node);
17763
+ if (contextualType) {
17764
+ const apparentType = mapType(contextualType, getApparentType, /*noReductions*/ true);
17765
+ if (apparentType.flags & TypeFlags.Union) {
17766
+ if (isObjectLiteralExpression(node)) {
17767
+ return discriminateContextualTypeByObjectMembers(node, apparentType as UnionType);
17768
+ }
17769
+ else if (isJsxAttributes(node)) {
17770
+ return discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType);
17771
+ }
17767
17772
}
17768
- else if (isJsxAttributes(node)) {
17769
- return discriminateContextualTypeByJSXAttributes(node, contextualType as UnionType);
17773
+ return apparentType;
17774
+ }
17775
+ }
17776
+
17777
+ // If the given contextual type contains instantiable types and if a mapper representing
17778
+ // return type inferences is available, instantiate those types using that mapper.
17779
+ function instantiateContextualType(contextualType: Type | undefined, node: Expression): Type | undefined {
17780
+ if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) {
17781
+ const returnMapper = (<InferenceContext>getContextualMapper(node)).returnMapper;
17782
+ if (returnMapper) {
17783
+ return instantiateInstantiableTypes(contextualType, returnMapper);
17770
17784
}
17771
17785
}
17772
17786
return contextualType;
17773
17787
}
17774
17788
17789
+ // This function is similar to instantiateType, except that (a) it only instantiates types that
17790
+ // are classified as instantiable (i.e. it doesn't instantiate object types), and (b) it performs
17791
+ // no reductions on instantiated union types.
17792
+ function instantiateInstantiableTypes(type: Type, mapper: TypeMapper): Type {
17793
+ if (type.flags & TypeFlags.Instantiable) {
17794
+ return instantiateType(type, mapper);
17795
+ }
17796
+ if (type.flags & TypeFlags.Union) {
17797
+ return getUnionType(map((<UnionType>type).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None);
17798
+ }
17799
+ if (type.flags & TypeFlags.Intersection) {
17800
+ return getIntersectionType(map((<IntersectionType>type).types, t => instantiateInstantiableTypes(t, mapper)));
17801
+ }
17802
+ return type;
17803
+ }
17804
+
17775
17805
/**
17776
17806
* Woah! Do you really want to use this function?
17777
17807
*
@@ -19910,6 +19940,9 @@ namespace ts {
19910
19940
const inferenceTargetType = getReturnTypeOfSignature(signature);
19911
19941
// Inferences made from return types have lower priority than all other inferences.
19912
19942
inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType);
19943
+ // Create a type mapper for instantiating generic contextual types using the inferences made
19944
+ // from the return type.
19945
+ context.returnMapper = cloneTypeMapper(context);
19913
19946
}
19914
19947
}
19915
19948
@@ -23020,7 +23053,12 @@ namespace ts {
23020
23053
context.contextualMapper = contextualMapper;
23021
23054
const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive :
23022
23055
contextualMapper ? CheckMode.Inferential : CheckMode.Contextual;
23023
- const result = checkExpression(node, checkMode);
23056
+ const type = checkExpression(node, checkMode);
23057
+ // We strip literal freshness when an appropriate contextual type is present such that contextually typed
23058
+ // literals always preserve their literal types (otherwise they might widen during type inference). An alternative
23059
+ // here would be to not mark contextually typed literals as fresh in the first place.
23060
+ const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node)) ?
23061
+ getRegularTypeOfLiteralType(type) : type;
23024
23062
context.contextualType = saveContextualType;
23025
23063
context.contextualMapper = saveContextualMapper;
23026
23064
return result;
@@ -23104,13 +23142,10 @@ namespace ts {
23104
23142
}
23105
23143
23106
23144
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type {
23107
- if (arguments.length === 2) {
23108
- contextualType = getContextualType(node);
23109
- }
23110
23145
const type = checkExpression(node, checkMode, forceTuple);
23111
23146
return isConstContext(node) ? getRegularTypeOfLiteralType(type) :
23112
23147
isTypeAssertion(node) ? type :
23113
- getWidenedLiteralLikeTypeForContextualType(type, contextualType);
23148
+ getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node) : contextualType, node) );
23114
23149
}
23115
23150
23116
23151
function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
0 commit comments