@@ -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;
@@ -4938,9 +4940,6 @@ namespace ts {
49384940 }
49394941 return objectTypeRelatedTo(<ObjectType>source, <ObjectType>target, /*reportErrors*/ false);
49404942 }
4941- if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
4942- return typeParameterIdenticalTo(<TypeParameter>source, <TypeParameter>target);
4943- }
49444943 if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
49454944 source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
49464945 if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target)) {
@@ -5071,20 +5070,6 @@ namespace ts {
50715070 return result;
50725071 }
50735072
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-
50885073 // Determine if two object types are related by structure. First, check if the result is already available in the global cache.
50895074 // Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
50905075 // 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 {
56075592 return Ternary.False;
56085593 }
56095594 }
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)) {
56245601 return Ternary.False;
56255602 }
56265603 // Spec 1.0 Section 3.8.3 & 3.8.4:
56275604 // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
56285605 source = getErasedSignature(source);
56295606 target = getErasedSignature(target);
5630- let targetLen = target.parameters.length;
5607+ let result = Ternary.True;
5608+ const targetLen = target.parameters.length;
56315609 for (let i = 0; i < targetLen; i++) {
56325610 let s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
56335611 let t = isRestParameterIndex(target, i) ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
@@ -5928,6 +5906,17 @@ namespace ts {
59285906 }
59295907
59305908 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+ }
59315920 if (target.flags & TypeFlags.TypeParameter) {
59325921 // If target is a type parameter, make an inference, unless the source type contains
59335922 // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
@@ -5938,8 +5927,7 @@ namespace ts {
59385927 if (source.flags & TypeFlags.ContainsAnyFunctionType) {
59395928 return;
59405929 }
5941-
5942- let typeParameters = context.typeParameters;
5930+ const typeParameters = context.typeParameters;
59435931 for (let i = 0; i < typeParameters.length; i++) {
59445932 if (target === typeParameters[i]) {
59455933 let inferences = context.inferences[i];
@@ -6086,6 +6074,41 @@ namespace ts {
60866074 }
60876075 }
60886076
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+
60896112 function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
60906113 let inferences = context.inferences[index];
60916114 return inferences.primary || inferences.secondary || emptyArray;
@@ -7859,7 +7882,6 @@ namespace ts {
78597882 return prop || unknownSymbol;
78607883 }
78617884
7862- let jsxElementClassType: Type = undefined;
78637885 function getJsxGlobalElementClassType(): Type {
78647886 if (!jsxElementClassType) {
78657887 jsxElementClassType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.ElementClass);
0 commit comments