@@ -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;
@@ -4938,9 +4940,6 @@ namespace ts {
4938
4940
}
4939
4941
return objectTypeRelatedTo(<ObjectType>source, <ObjectType>target, /*reportErrors*/ false);
4940
4942
}
4941
- if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
4942
- return typeParameterIdenticalTo(<TypeParameter>source, <TypeParameter>target);
4943
- }
4944
4943
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
4945
4944
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
4946
4945
if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target)) {
@@ -5071,20 +5070,6 @@ namespace ts {
5071
5070
return result;
5072
5071
}
5073
5072
5074
- function typeParameterIdenticalTo(source: TypeParameter, target: TypeParameter): Ternary {
5075
- if (source.symbol.name !== target.symbol.name) {
5076
- return Ternary.False;
5077
- }
5078
- // covers case when both type parameters does not have constraint (both equal to noConstraintType)
5079
- if (source.constraint === target.constraint) {
5080
- return Ternary.True;
5081
- }
5082
- if (source.constraint === noConstraintType || target.constraint === noConstraintType) {
5083
- return Ternary.False;
5084
- }
5085
- return isIdenticalTo(source.constraint, target.constraint);
5086
- }
5087
-
5088
5073
// Determine if two object types are related by structure. First, check if the result is already available in the global cache.
5089
5074
// Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
5090
5075
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
@@ -5607,27 +5592,20 @@ namespace ts {
5607
5592
return Ternary.False;
5608
5593
}
5609
5594
}
5610
- let result = Ternary.True;
5611
- if (source.typeParameters && target.typeParameters) {
5612
- if (source.typeParameters.length !== target.typeParameters.length) {
5613
- return Ternary.False;
5614
- }
5615
- for (let i = 0, len = source.typeParameters.length; i < len; ++i) {
5616
- let related = compareTypes(source.typeParameters[i], target.typeParameters[i]);
5617
- if (!related) {
5618
- return Ternary.False;
5619
- }
5620
- result &= related;
5621
- }
5622
- }
5623
- else if (source.typeParameters || target.typeParameters) {
5595
+ // Check that the two signatures have the same number of type parameters. We might consider
5596
+ // also checking that any type parameter constraints match, but that would require instantiating
5597
+ // the constraints with a common set of type arguments to get relatable entities in places where
5598
+ // type parameters occur in the constraints. The complexity of doing that doesn't seem worthwhile,
5599
+ // particularly as we're comparing erased versions of the signatures below.
5600
+ if ((source.typeParameters ? source.typeParameters.length : 0) !== (target.typeParameters ? target.typeParameters.length : 0)) {
5624
5601
return Ternary.False;
5625
5602
}
5626
5603
// Spec 1.0 Section 3.8.3 & 3.8.4:
5627
5604
// M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
5628
5605
source = getErasedSignature(source);
5629
5606
target = getErasedSignature(target);
5630
- let targetLen = target.parameters.length;
5607
+ let result = Ternary.True;
5608
+ const targetLen = target.parameters.length;
5631
5609
for (let i = 0; i < targetLen; i++) {
5632
5610
let s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
5633
5611
let t = isRestParameterIndex(target, i) ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
@@ -5928,6 +5906,17 @@ namespace ts {
5928
5906
}
5929
5907
5930
5908
function inferFromTypes(source: Type, target: Type) {
5909
+ if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
5910
+ source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
5911
+ // Source and target are both unions or both intersections. To improve the quality of
5912
+ // inferences we first reduce the types by removing constituents that are identically
5913
+ // matched by a constituent in the other type. For example, when inferring from
5914
+ // 'string | string[]' to 'string | T', we reduce the types to 'string[]' and 'T'.
5915
+ const reducedSource = reduceUnionOrIntersectionType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target);
5916
+ const reducedTarget = reduceUnionOrIntersectionType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source);
5917
+ source = reducedSource;
5918
+ target = reducedTarget;
5919
+ }
5931
5920
if (target.flags & TypeFlags.TypeParameter) {
5932
5921
// If target is a type parameter, make an inference, unless the source type contains
5933
5922
// the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
@@ -5938,8 +5927,7 @@ namespace ts {
5938
5927
if (source.flags & TypeFlags.ContainsAnyFunctionType) {
5939
5928
return;
5940
5929
}
5941
-
5942
- let typeParameters = context.typeParameters;
5930
+ const typeParameters = context.typeParameters;
5943
5931
for (let i = 0; i < typeParameters.length; i++) {
5944
5932
if (target === typeParameters[i]) {
5945
5933
let inferences = context.inferences[i];
@@ -6086,6 +6074,41 @@ namespace ts {
6086
6074
}
6087
6075
}
6088
6076
6077
+ function typeIdenticalToSomeType(source: Type, target: UnionOrIntersectionType): boolean {
6078
+ for (const t of target.types) {
6079
+ if (isTypeIdenticalTo(source, t)) {
6080
+ return true;
6081
+ }
6082
+ }
6083
+ return false;
6084
+ }
6085
+
6086
+ /**
6087
+ * Return the reduced form of the source type. This type is computed by by removing all source
6088
+ * constituents that have an identical match in the target type.
6089
+ */
6090
+ function reduceUnionOrIntersectionType(source: UnionOrIntersectionType, target: UnionOrIntersectionType) {
6091
+ let sourceTypes = source.types;
6092
+ let sourceIndex = 0;
6093
+ let modified = false;
6094
+ while (sourceIndex < sourceTypes.length) {
6095
+ if (typeIdenticalToSomeType(sourceTypes[sourceIndex], target)) {
6096
+ if (!modified) {
6097
+ sourceTypes = sourceTypes.slice(0);
6098
+ modified = true;
6099
+ }
6100
+ sourceTypes.splice(sourceIndex, 1);
6101
+ }
6102
+ else {
6103
+ sourceIndex++;
6104
+ }
6105
+ }
6106
+ if (modified) {
6107
+ return source.flags & TypeFlags.Union ? getUnionType(sourceTypes, /*noSubtypeReduction*/ true) : getIntersectionType(sourceTypes);
6108
+ }
6109
+ return source;
6110
+ }
6111
+
6089
6112
function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
6090
6113
let inferences = context.inferences[index];
6091
6114
return inferences.primary || inferences.secondary || emptyArray;
@@ -7859,7 +7882,6 @@ namespace ts {
7859
7882
return prop || unknownSymbol;
7860
7883
}
7861
7884
7862
- let jsxElementClassType: Type = undefined;
7863
7885
function getJsxGlobalElementClassType(): Type {
7864
7886
if (!jsxElementClassType) {
7865
7887
jsxElementClassType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.ElementClass);
0 commit comments