diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f8326c1fac..8ef7b3453a2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15310,7 +15310,7 @@ namespace ts { objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeVariables) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & ObjectFlags.Mapped || - type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeVariables(type)); + type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && couldUnionOrIntersectionContainTypeVariables(type)); } function couldUnionOrIntersectionContainTypeVariables(type: UnionOrIntersectionType): boolean { @@ -15487,37 +15487,47 @@ namespace ts { inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); return; } - if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && !(source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) || - source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { - // Source and target are both unions or both intersections. If source and target - // are the same type, just relate each constituent type to itself. - if (source === target) { - for (const t of (source).types) { - inferFromTypes(t, t); - } - return; + if (source === target && source.flags & TypeFlags.UnionOrIntersection) { + // When source and target are the same union or intersection type, just relate each constituent + // type to itself. + for (const t of (source).types) { + inferFromTypes(t, t); } - // First, infer between exactly matching source and target constituents and remove - // the matching types. Types exactly match when they are identical or, in union - // types, when the source is a literal and the target is the corresponding primitive. - const matching = target.flags & TypeFlags.Union ? isTypeOrBaseIdenticalTo : isTypeIdenticalTo; - const [tempSources, tempTargets] = inferFromMatchingTypes((source).types, (target).types, matching); - // Next, infer between closely matching source and target constituents and remove - // the matching types. Types closely match when they are instantiations of the same - // object type or instantiations of the same type alias. - const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy); - if (sources.length === 0 || targets.length === 0) { - return; - } - source = source.flags & TypeFlags.Union ? getUnionType(sources) : getIntersectionType(sources); - target = target.flags & TypeFlags.Union ? getUnionType(targets) : getIntersectionType(targets); + return; } - else if (target.flags & TypeFlags.Union && !(target.flags & TypeFlags.EnumLiteral) || target.flags & TypeFlags.Intersection) { - // This block of code is an optimized version of the block above for the simpler case - // of a singleton source type. - const matching = target.flags & TypeFlags.Union ? isTypeOrBaseIdenticalTo : isTypeIdenticalTo; - if (inferFromMatchingType(source, (target).types, matching)) return; - if (inferFromMatchingType(source, (target).types, isTypeCloselyMatchedBy)) return; + if (target.flags & TypeFlags.Union) { + if (source.flags & TypeFlags.Union) { + // First, infer between identically matching source and target constituents and remove the + // matching types. + const [tempSources, tempTargets] = inferFromMatchingTypes((source).types, (target).types, isTypeOrBaseIdenticalTo); + // Next, infer between closely matching source and target constituents and remove + // the matching types. Types closely match when they are instantiations of the same + // object type or instantiations of the same type alias. + const [sources, targets] = inferFromMatchingTypes(tempSources, tempTargets, isTypeCloselyMatchedBy); + if (sources.length === 0 || targets.length === 0) { + return; + } + source = getUnionType(sources); + target = getUnionType(targets); + } + else { + if (inferFromMatchingType(source, (target).types, isTypeOrBaseIdenticalTo)) return; + if (inferFromMatchingType(source, (target).types, isTypeCloselyMatchedBy)) return; + } + } + else if (target.flags & TypeFlags.Intersection && some((target).types, t => !!getInferenceInfoForType(t))) { + if (source.flags & TypeFlags.Intersection) { + // Infer between identically matching source and target constituents and remove the matching types. + const [sources, targets] = inferFromMatchingTypes((source).types, (target).types, isTypeIdenticalTo); + if (sources.length === 0 || targets.length === 0) { + return; + } + source = getIntersectionType(sources); + target = getIntersectionType(targets); + } + else if (!(source.flags & TypeFlags.Union)) { + if (inferFromMatchingType(source, (target).types, isTypeIdenticalTo)) return; + } } else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { target = getActualTypeVariable(target);