@@ -15458,6 +15458,7 @@ namespace ts {
15458
15458
let visited: Map<boolean>;
15459
15459
let bivariant = false;
15460
15460
let propagationType: Type;
15461
+ let inferenceCount = 0;
15461
15462
let allowComplexConstraintInference = true;
15462
15463
inferFromTypes(originalSource, originalTarget);
15463
15464
@@ -15561,6 +15562,7 @@ namespace ts {
15561
15562
clearCachedInferences(inferences);
15562
15563
}
15563
15564
}
15565
+ inferenceCount++;
15564
15566
return;
15565
15567
}
15566
15568
else {
@@ -15610,13 +15612,16 @@ namespace ts {
15610
15612
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
15611
15613
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
15612
15614
}
15615
+ else if (target.flags & TypeFlags.Union) {
15616
+ inferToUnionType(source, <UnionType>target);
15617
+ }
15618
+ else if (target.flags & TypeFlags.Intersection) {
15619
+ inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, /*isIntersection*/ true);
15620
+ }
15613
15621
else if (target.flags & TypeFlags.Conditional && !contravariant) {
15614
15622
const targetTypes = [getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)];
15615
15623
inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false);
15616
15624
}
15617
- else if (target.flags & TypeFlags.UnionOrIntersection) {
15618
- inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, !!(target.flags & TypeFlags.Intersection));
15619
- }
15620
15625
else if (source.flags & TypeFlags.Union) {
15621
15626
// Source is a union or intersection type, infer from each constituent type
15622
15627
const sourceTypes = (<UnionOrIntersectionType>source).types;
@@ -15742,6 +15747,46 @@ namespace ts {
15742
15747
}
15743
15748
}
15744
15749
15750
+ function inferToUnionType(source: Type, target: UnionType) {
15751
+ const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
15752
+ const matched = new Array<boolean>(sources.length);
15753
+ let typeVariableCount = 0;
15754
+ // First infer to types that are not naked type variables. For each source type we
15755
+ // track whether inferences were made from that particular type to some target.
15756
+ for (const t of target.types) {
15757
+ if (getInferenceInfoForType(t)) {
15758
+ typeVariableCount++;
15759
+ }
15760
+ else {
15761
+ for (let i = 0; i < sources.length; i++) {
15762
+ const count = inferenceCount;
15763
+ inferFromTypes(sources[i], t);
15764
+ if (count !== inferenceCount) matched[i] = true;
15765
+ }
15766
+ }
15767
+ }
15768
+ // If there are naked type variables in the target, create a union of the source types
15769
+ // from which no inferences have been made so far and infer from that union to each naked
15770
+ // type variable. If there is more than one naked type variable, give lower priority to
15771
+ // the inferences as they are less specific.
15772
+ if (typeVariableCount > 0) {
15773
+ const unmatched = flatMap(sources, (s, i) => matched![i] ? undefined : s);
15774
+ if (unmatched.length) {
15775
+ const s = getUnionType(unmatched);
15776
+ const savePriority = priority;
15777
+ if (typeVariableCount > 1) {
15778
+ priority |= InferencePriority.NakedTypeVariable;
15779
+ }
15780
+ for (const t of target.types) {
15781
+ if (getInferenceInfoForType(t)) {
15782
+ inferFromTypes(s, t);
15783
+ }
15784
+ }
15785
+ priority = savePriority;
15786
+ }
15787
+ }
15788
+ }
15789
+
15745
15790
function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean {
15746
15791
if (constraintType.flags & TypeFlags.Union) {
15747
15792
let result = false;
0 commit comments