@@ -43,6 +43,8 @@ namespace ts {
43
43
let emptyArray: any[] = [];
44
44
let emptySymbols: SymbolTable = {};
45
45
46
+ let jsxElementClassType: Type = undefined;
47
+
46
48
let compilerOptions = host.getCompilerOptions();
47
49
let languageVersion = compilerOptions.target || ScriptTarget.ES3;
48
50
let modulekind = compilerOptions.module ? compilerOptions.module : languageVersion === ScriptTarget.ES6 ? ModuleKind.ES6 : ModuleKind.None;
@@ -5928,6 +5930,17 @@ namespace ts {
5928
5930
}
5929
5931
5930
5932
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
+ }
5931
5944
if (target.flags & TypeFlags.TypeParameter) {
5932
5945
// If target is a type parameter, make an inference, unless the source type contains
5933
5946
// the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
@@ -5938,8 +5951,7 @@ namespace ts {
5938
5951
if (source.flags & TypeFlags.ContainsAnyFunctionType) {
5939
5952
return;
5940
5953
}
5941
-
5942
- let typeParameters = context.typeParameters;
5954
+ const typeParameters = context.typeParameters;
5943
5955
for (let i = 0; i < typeParameters.length; i++) {
5944
5956
if (target === typeParameters[i]) {
5945
5957
let inferences = context.inferences[i];
@@ -6086,6 +6098,41 @@ namespace ts {
6086
6098
}
6087
6099
}
6088
6100
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
+
6089
6136
function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
6090
6137
let inferences = context.inferences[index];
6091
6138
return inferences.primary || inferences.secondary || emptyArray;
@@ -7859,7 +7906,6 @@ namespace ts {
7859
7906
return prop || unknownSymbol;
7860
7907
}
7861
7908
7862
- let jsxElementClassType: Type = undefined;
7863
7909
function getJsxGlobalElementClassType(): Type {
7864
7910
if (!jsxElementClassType) {
7865
7911
jsxElementClassType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.ElementClass);
0 commit comments