@@ -43,6 +43,8 @@ namespace ts {
4343 let emptyArray: any[] = [];
4444 let emptySymbols: SymbolTable = {};
4545
46+ let jsxElementClassType: Type = undefined;
47+
4648 let compilerOptions = host.getCompilerOptions();
4749 let languageVersion = compilerOptions.target || ScriptTarget.ES3;
4850 let modulekind = compilerOptions.module ? compilerOptions.module : languageVersion === ScriptTarget.ES6 ? ModuleKind.ES6 : ModuleKind.None;
@@ -5928,6 +5930,17 @@ namespace ts {
59285930 }
59295931
59305932 function inferFromTypes(source: Type, target: Type) {
5933+ if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
5934+ source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
5935+ // Source and target are both unions or both intersections. To improve the quality of
5936+ // inferences we first reduce the types by removing constituents that are identically
5937+ // matched by a constituent in the other type. For example, when inferring from
5938+ // 'string | string[]' to 'string | T', we reduce the types to 'string[]' and 'T'.
5939+ const reducedSource = reduceUnionOrIntersectionType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target);
5940+ const reducedTarget = reduceUnionOrIntersectionType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source);
5941+ source = reducedSource;
5942+ target = reducedTarget;
5943+ }
59315944 if (target.flags & TypeFlags.TypeParameter) {
59325945 // If target is a type parameter, make an inference, unless the source type contains
59335946 // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
@@ -5938,8 +5951,7 @@ namespace ts {
59385951 if (source.flags & TypeFlags.ContainsAnyFunctionType) {
59395952 return;
59405953 }
5941-
5942- let typeParameters = context.typeParameters;
5954+ const typeParameters = context.typeParameters;
59435955 for (let i = 0; i < typeParameters.length; i++) {
59445956 if (target === typeParameters[i]) {
59455957 let inferences = context.inferences[i];
@@ -6086,6 +6098,41 @@ namespace ts {
60866098 }
60876099 }
60886100
6101+ function typeIdenticalToSomeType(source: Type, target: UnionOrIntersectionType): boolean {
6102+ for (const t of target.types) {
6103+ if (isTypeIdenticalTo(source, t)) {
6104+ return true;
6105+ }
6106+ }
6107+ return false;
6108+ }
6109+
6110+ /**
6111+ * Return the reduced form of the source type. This type is computed by by removing all source
6112+ * constituents that have an identical match in the target type.
6113+ */
6114+ function reduceUnionOrIntersectionType(source: UnionOrIntersectionType, target: UnionOrIntersectionType) {
6115+ let sourceTypes = source.types;
6116+ let sourceIndex = 0;
6117+ let modified = false;
6118+ while (sourceIndex < sourceTypes.length) {
6119+ if (typeIdenticalToSomeType(sourceTypes[sourceIndex], target)) {
6120+ if (!modified) {
6121+ sourceTypes = sourceTypes.slice(0);
6122+ modified = true;
6123+ }
6124+ sourceTypes.splice(sourceIndex, 1);
6125+ }
6126+ else {
6127+ sourceIndex++;
6128+ }
6129+ }
6130+ if (modified) {
6131+ return source.flags & TypeFlags.Union ? getUnionType(sourceTypes, /*noSubtypeReduction*/ true) : getIntersectionType(sourceTypes);
6132+ }
6133+ return source;
6134+ }
6135+
60896136 function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
60906137 let inferences = context.inferences[index];
60916138 return inferences.primary || inferences.secondary || emptyArray;
@@ -7859,7 +7906,6 @@ namespace ts {
78597906 return prop || unknownSymbol;
78607907 }
78617908
7862- let jsxElementClassType: Type = undefined;
78637909 function getJsxGlobalElementClassType(): Type {
78647910 if (!jsxElementClassType) {
78657911 jsxElementClassType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.ElementClass);
0 commit comments