@@ -15568,42 +15568,45 @@ namespace ts {
15568
15568
return;
15569
15569
}
15570
15570
if (target.flags & TypeFlags.Union) {
15571
- if (source.flags & TypeFlags.Union) {
15572
- // First, infer between identically matching source and target constituents and remove the
15573
- // matching types.
15574
- const [tempSources, tempTargets] = inferFromMatchingTypes((<UnionType>source).types, (<UnionType>target).types, isTypeOrBaseIdenticalTo);
15575
- // Next, infer between closely matching source and target constituents and remove
15576
- // the matching types. Types closely match when they are instantiations of the same
15577
- // object type or instantiations of the same type alias.
15578
- const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy);
15579
- if (sources.length === 0 || targets.length === 0) {
15580
- return;
15581
- }
15582
- source = getUnionType(sources);
15583
- target = getUnionType(targets);
15571
+ // First, infer between identically matching source and target constituents and remove the
15572
+ // matching types.
15573
+ const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (<UnionType>source).types : [source], (<UnionType>target).types, isTypeOrBaseIdenticalTo);
15574
+ // Next, infer between closely matching source and target constituents and remove
15575
+ // the matching types. Types closely match when they are instantiations of the same
15576
+ // object type or instantiations of the same type alias.
15577
+ const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy);
15578
+ if (targets.length === 0) {
15579
+ return;
15584
15580
}
15585
- else {
15586
- if (inferFromMatchingType(source, (<UnionType>target).types, isTypeOrBaseIdenticalTo)) return;
15587
- if (inferFromMatchingType(source, (<UnionType>target).types, isTypeCloselyMatchedBy)) return;
15581
+ target = getUnionType(targets);
15582
+ if (sources.length === 0) {
15583
+ // All source constituents have been matched and there is nothing further to infer from.
15584
+ // However, simply making no inferences is undesirable because it could ultimately mean
15585
+ // inferring a type parameter constraint. Instead, make a lower priority inference from
15586
+ // the full source to whatever remains in the target. For example, when inferring from
15587
+ // string to 'string | T', make a lower priority inference of string for T.
15588
+ const savePriority = priority;
15589
+ priority |= InferencePriority.NakedTypeVariable;
15590
+ inferFromTypes(source, target);
15591
+ priority = savePriority;
15592
+ return;
15588
15593
}
15594
+ source = getUnionType(sources);
15589
15595
}
15590
15596
else if (target.flags & TypeFlags.Intersection && some((<IntersectionType>target).types, t => !!getInferenceInfoForType(t))) {
15591
15597
// We reduce intersection types only when they contain naked type parameters. For example, when
15592
15598
// inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and
15593
15599
// infer { extra: any } for T. But when inferring to 'string[] & Iterable<T>' we want to keep the
15594
15600
// string[] on the source side and infer string for T.
15595
- if (source.flags & TypeFlags.Intersection ) {
15601
+ if (!( source.flags & TypeFlags.Union) ) {
15596
15602
// Infer between identically matching source and target constituents and remove the matching types.
15597
- const [sources, targets] = inferFromMatchingTypes((<IntersectionType>source).types, (<IntersectionType>target).types, isTypeIdenticalTo);
15603
+ const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (<IntersectionType>source).types : [source] , (<IntersectionType>target).types, isTypeIdenticalTo);
15598
15604
if (sources.length === 0 || targets.length === 0) {
15599
15605
return;
15600
15606
}
15601
15607
source = getIntersectionType(sources);
15602
15608
target = getIntersectionType(targets);
15603
15609
}
15604
- else if (!(source.flags & TypeFlags.Union)) {
15605
- if (inferFromMatchingType(source, (<IntersectionType>target).types, isTypeIdenticalTo)) return;
15606
- }
15607
15610
}
15608
15611
else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
15609
15612
target = getActualTypeVariable(target);
@@ -15753,17 +15756,6 @@ namespace ts {
15753
15756
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
15754
15757
}
15755
15758
15756
- function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean) {
15757
- let matched = false;
15758
- for (const t of targets) {
15759
- if (matches(source, t)) {
15760
- inferFromTypes(source, t);
15761
- matched = true;
15762
- }
15763
- }
15764
- return matched;
15765
- }
15766
-
15767
15759
function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] {
15768
15760
let matchedSources: Type[] | undefined;
15769
15761
let matchedTargets: Type[] | undefined;
0 commit comments