diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 57e34d86080a7..759bb2bb6b82f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10616,6 +10616,7 @@ namespace ts { } let result = Ternary.False; + let strongIntersectionTarget: Type | undefined; const saveErrorInfo = errorInfo; const saveIsIntersectionConstituent = isIntersectionConstituent; isIntersectionConstituent = false; @@ -10635,6 +10636,23 @@ namespace ts { else if (target.flags & TypeFlags.Intersection) { isIntersectionConstituent = true; result = typeRelatedToEachType(source, target as IntersectionType, reportErrors); + + // We don't report errors at first. If the types aren't related then we'll try to see if + // the intersection contains any "weak" types that aren't contributing anything to relating the two types + // (but carefully in case *all* the types in the target are weak). + // If so, we'll drop them and report the error on a smaller intersection which should be more readable. + // If not, re-trigger the original relationship check. + result = typeRelatedToEachType(source, target as IntersectionType, /*reportErrors*/ false); + if (reportErrors && !result && some((target as IntersectionType).types, isWeakType) && !isWeakType(target)) { + const constituents = filter((target as IntersectionType).types, t => !isWeakType(t)); + Debug.assert(!!constituents.length, "Should have at least one non-weak constituent result."); + Debug.assert(constituents.length < (target as IntersectionType).types.length, "Should have fewer constituents"); + strongIntersectionTarget = getIntersectionType(constituents); + if (isRelatedTo(source, strongIntersectionTarget, reportErrors)) { + typeRelatedToEachType(source, target as IntersectionType, reportErrors); + strongIntersectionTarget = undefined; + } + } } else if (source.flags & TypeFlags.Intersection) { // Check to see if any constituents of the intersection are immediately related to the target. @@ -10679,6 +10697,11 @@ namespace ts { isIntersectionConstituent = saveIsIntersectionConstituent; if (!result && reportErrors) { + if (strongIntersectionTarget) { + // Should have reported an error above. + return result; + } + if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) { tryElaborateErrorsForPrimitivesAndObjects(source, target); } diff --git a/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt index cf999188ebc59..26676a08b2996 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt +++ b/tests/baselines/reference/checkJsxChildrenProperty14.errors.txt @@ -1,7 +1,8 @@ tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'. - Types of property 'children' are incompatible. - Type 'Element[]' is not assignable to type 'Element'. - Property 'type' is missing in type 'Element[]'. + Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'. + Types of property 'children' are incompatible. + Type 'Element[]' is not assignable to type 'Element'. + Property 'type' is missing in type 'Element[]'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -49,6 +50,7 @@ tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Ele let k5 = <>