@@ -17354,10 +17354,7 @@ namespace ts {
17354
17354
// inferring a type parameter constraint. Instead, make a lower priority inference from
17355
17355
// the full source to whatever remains in the target. For example, when inferring from
17356
17356
// string to 'string | T', make a lower priority inference of string for T.
17357
- const savePriority = priority;
17358
- priority |= InferencePriority.NakedTypeVariable;
17359
- inferFromTypes(source, target);
17360
- priority = savePriority;
17357
+ inferWithPriority(source, target, InferencePriority.NakedTypeVariable);
17361
17358
return;
17362
17359
}
17363
17360
source = getUnionType(sources);
@@ -17459,10 +17456,7 @@ namespace ts {
17459
17456
else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) {
17460
17457
const empty = createEmptyObjectTypeFromStringLiteral(source);
17461
17458
contravariant = !contravariant;
17462
- const savePriority = priority;
17463
- priority |= InferencePriority.LiteralKeyof;
17464
- inferFromTypes(empty, (target as IndexType).type);
17465
- priority = savePriority;
17459
+ inferWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof);
17466
17460
contravariant = !contravariant;
17467
17461
}
17468
17462
else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
@@ -17514,6 +17508,13 @@ namespace ts {
17514
17508
}
17515
17509
}
17516
17510
17511
+ function inferWithPriority(source: Type, target: Type, newPriority: InferencePriority) {
17512
+ const savePriority = priority;
17513
+ priority |= newPriority;
17514
+ inferFromTypes(source, target);
17515
+ priority = savePriority;
17516
+ }
17517
+
17517
17518
function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) {
17518
17519
const key = source.id + "," + target.id;
17519
17520
const status = visited && visited.get(key);
@@ -17581,6 +17582,18 @@ namespace ts {
17581
17582
return undefined;
17582
17583
}
17583
17584
17585
+ function getSingleTypeVariableFromIntersectionTypes(types: Type[]) {
17586
+ let typeVariable: Type | undefined;
17587
+ for (const type of types) {
17588
+ const t = type.flags & TypeFlags.Intersection && find((<IntersectionType>type).types, t => !!getInferenceInfoForType(t));
17589
+ if (!t || typeVariable && t !== typeVariable) {
17590
+ return undefined;
17591
+ }
17592
+ typeVariable = t;
17593
+ }
17594
+ return typeVariable;
17595
+ }
17596
+
17584
17597
function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) {
17585
17598
let typeVariableCount = 0;
17586
17599
if (targetFlags & TypeFlags.Union) {
@@ -17608,6 +17621,16 @@ namespace ts {
17608
17621
}
17609
17622
}
17610
17623
}
17624
+ if (typeVariableCount === 0) {
17625
+ // If every target is an intersection of types containing a single naked type variable,
17626
+ // make a lower priority inference to that type variable. This handles inferring from
17627
+ // 'A | B' to 'T & (X | Y)' where we want to infer 'A | B' for T.
17628
+ const intersectionTypeVariable = getSingleTypeVariableFromIntersectionTypes(targets);
17629
+ if (intersectionTypeVariable) {
17630
+ inferWithPriority(source, intersectionTypeVariable, InferencePriority.NakedTypeVariable);
17631
+ }
17632
+ return;
17633
+ }
17611
17634
// If the target has a single naked type variable and no inference circularities were
17612
17635
// encountered above (meaning we explored the types fully), create a union of the source
17613
17636
// types from which no inferences have been made so far and infer from that union to the
@@ -17638,14 +17661,11 @@ namespace ts {
17638
17661
// we want to infer string for T, not Promise<string> | string. For intersection types
17639
17662
// we only infer to single naked type variables.
17640
17663
if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) {
17641
- const savePriority = priority;
17642
- priority |= InferencePriority.NakedTypeVariable;
17643
17664
for (const t of targets) {
17644
17665
if (getInferenceInfoForType(t)) {
17645
- inferFromTypes (source, t);
17666
+ inferWithPriority (source, t, InferencePriority.NakedTypeVariable );
17646
17667
}
17647
17668
}
17648
- priority = savePriority;
17649
17669
}
17650
17670
}
17651
17671
@@ -17666,25 +17686,21 @@ namespace ts {
17666
17686
if (inference && !inference.isFixed) {
17667
17687
const inferredType = inferTypeForHomomorphicMappedType(source, target, <IndexType>constraintType);
17668
17688
if (inferredType) {
17669
- const savePriority = priority;
17670
17689
// We assign a lower priority to inferences made from types containing non-inferrable
17671
17690
// types because we may only have a partial result (i.e. we may have failed to make
17672
17691
// reverse inferences for some properties).
17673
- priority |= getObjectFlags(source) & ObjectFlags.NonInferrableType ?
17674
- InferencePriority.PartialHomomorphicMappedType : InferencePriority.HomomorphicMappedType;
17675
- inferFromTypes(inferredType, inference.typeParameter);
17676
- priority = savePriority ;
17692
+ inferWithPriority(inferredType, inference.typeParameter,
17693
+ getObjectFlags(source) & ObjectFlags.NonInferrableType ?
17694
+ InferencePriority.PartialHomomorphicMappedType :
17695
+ InferencePriority.HomomorphicMappedType) ;
17677
17696
}
17678
17697
}
17679
17698
return true;
17680
17699
}
17681
17700
if (constraintType.flags & TypeFlags.TypeParameter) {
17682
17701
// We're inferring from some source type S to a mapped type { [P in K]: X }, where K is a type
17683
17702
// parameter. First infer from 'keyof S' to K.
17684
- const savePriority = priority;
17685
- priority |= InferencePriority.MappedTypeConstraint;
17686
- inferFromTypes(getIndexType(source), constraintType);
17687
- priority = savePriority;
17703
+ inferWithPriority(getIndexType(source), constraintType, InferencePriority.MappedTypeConstraint);
17688
17704
// If K is constrained to a type C, also infer to C. Thus, for a mapped type { [P in K]: X },
17689
17705
// where K extends keyof T, we make the same inferences as for a homomorphic mapped type
17690
17706
// { [P in keyof T]: X }. This enables us to make meaningful inferences when the target is a
0 commit comments