diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 016ce44683c8a..01f9be10f2201 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18362,7 +18362,7 @@ namespace ts { // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't // appear to be comparable to '2'. if (relation === comparableRelation && target.flags & TypeFlags.Primitive) { - const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Primitive ? t : getBaseConstraintOfType(t) || unknownType); + const constraints = sameMap((source as IntersectionType).types, getBaseConstraintOrType); if (constraints !== (source as IntersectionType).types) { source = getIntersectionType(constraints); if (!(source.flags & TypeFlags.Intersection)) { diff --git a/tests/baselines/reference/intersectionOfUnionNarrowing.js b/tests/baselines/reference/intersectionOfUnionNarrowing.js new file mode 100644 index 0000000000000..b3871e4c8bc98 --- /dev/null +++ b/tests/baselines/reference/intersectionOfUnionNarrowing.js @@ -0,0 +1,26 @@ +//// [intersectionOfUnionNarrowing.ts] +interface X { + a?: { aProp: string }; + b?: { bProp: string }; +} +type AorB = { a: object; b: undefined } | { a: undefined; b: object }; + +declare const q: X & AorB; + +if (q.a !== undefined) { + q.a.aProp; +} else { + // q.b is previously incorrectly inferred as potentially undefined + q.b.bProp; +} + + +//// [intersectionOfUnionNarrowing.js] +"use strict"; +if (q.a !== undefined) { + q.a.aProp; +} +else { + // q.b is previously incorrectly inferred as potentially undefined + q.b.bProp; +} diff --git a/tests/baselines/reference/intersectionOfUnionNarrowing.symbols b/tests/baselines/reference/intersectionOfUnionNarrowing.symbols new file mode 100644 index 0000000000000..0ab98b95fb06a --- /dev/null +++ b/tests/baselines/reference/intersectionOfUnionNarrowing.symbols @@ -0,0 +1,47 @@ +=== tests/cases/conformance/types/intersection/intersectionOfUnionNarrowing.ts === +interface X { +>X : Symbol(X, Decl(intersectionOfUnionNarrowing.ts, 0, 0)) + + a?: { aProp: string }; +>a : Symbol(X.a, Decl(intersectionOfUnionNarrowing.ts, 0, 13)) +>aProp : Symbol(aProp, Decl(intersectionOfUnionNarrowing.ts, 1, 7)) + + b?: { bProp: string }; +>b : Symbol(X.b, Decl(intersectionOfUnionNarrowing.ts, 1, 24)) +>bProp : Symbol(bProp, Decl(intersectionOfUnionNarrowing.ts, 2, 7)) +} +type AorB = { a: object; b: undefined } | { a: undefined; b: object }; +>AorB : Symbol(AorB, Decl(intersectionOfUnionNarrowing.ts, 3, 1)) +>a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 4, 13)) +>b : Symbol(b, Decl(intersectionOfUnionNarrowing.ts, 4, 24)) +>a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 4, 43)) +>b : Symbol(b, Decl(intersectionOfUnionNarrowing.ts, 4, 57)) + +declare const q: X & AorB; +>q : Symbol(q, Decl(intersectionOfUnionNarrowing.ts, 6, 13)) +>X : Symbol(X, Decl(intersectionOfUnionNarrowing.ts, 0, 0)) +>AorB : Symbol(AorB, Decl(intersectionOfUnionNarrowing.ts, 3, 1)) + +if (q.a !== undefined) { +>q.a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 13), Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 43)) +>q : Symbol(q, Decl(intersectionOfUnionNarrowing.ts, 6, 13)) +>a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 13), Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 43)) +>undefined : Symbol(undefined) + + q.a.aProp; +>q.a.aProp : Symbol(aProp, Decl(intersectionOfUnionNarrowing.ts, 1, 7)) +>q.a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 13)) +>q : Symbol(q, Decl(intersectionOfUnionNarrowing.ts, 6, 13)) +>a : Symbol(a, Decl(intersectionOfUnionNarrowing.ts, 0, 13), Decl(intersectionOfUnionNarrowing.ts, 4, 13)) +>aProp : Symbol(aProp, Decl(intersectionOfUnionNarrowing.ts, 1, 7)) + +} else { + // q.b is previously incorrectly inferred as potentially undefined + q.b.bProp; +>q.b.bProp : Symbol(bProp, Decl(intersectionOfUnionNarrowing.ts, 2, 7)) +>q.b : Symbol(b, Decl(intersectionOfUnionNarrowing.ts, 1, 24), Decl(intersectionOfUnionNarrowing.ts, 4, 57)) +>q : Symbol(q, Decl(intersectionOfUnionNarrowing.ts, 6, 13)) +>b : Symbol(b, Decl(intersectionOfUnionNarrowing.ts, 1, 24), Decl(intersectionOfUnionNarrowing.ts, 4, 57)) +>bProp : Symbol(bProp, Decl(intersectionOfUnionNarrowing.ts, 2, 7)) +} + diff --git a/tests/baselines/reference/intersectionOfUnionNarrowing.types b/tests/baselines/reference/intersectionOfUnionNarrowing.types new file mode 100644 index 0000000000000..27dc8f3dc6c6c --- /dev/null +++ b/tests/baselines/reference/intersectionOfUnionNarrowing.types @@ -0,0 +1,44 @@ +=== tests/cases/conformance/types/intersection/intersectionOfUnionNarrowing.ts === +interface X { + a?: { aProp: string }; +>a : { aProp: string; } | undefined +>aProp : string + + b?: { bProp: string }; +>b : { bProp: string; } | undefined +>bProp : string +} +type AorB = { a: object; b: undefined } | { a: undefined; b: object }; +>AorB : AorB +>a : object +>b : undefined +>a : undefined +>b : object + +declare const q: X & AorB; +>q : X & AorB + +if (q.a !== undefined) { +>q.a !== undefined : boolean +>q.a : ({ aProp: string; } & object) | undefined +>q : X & AorB +>a : ({ aProp: string; } & object) | undefined +>undefined : undefined + + q.a.aProp; +>q.a.aProp : string +>q.a : { aProp: string; } & object +>q : X & { a: object; b: undefined; } +>a : { aProp: string; } & object +>aProp : string + +} else { + // q.b is previously incorrectly inferred as potentially undefined + q.b.bProp; +>q.b.bProp : string +>q.b : { bProp: string; } & object +>q : X & { a: undefined; b: object; } +>b : { bProp: string; } & object +>bProp : string +} + diff --git a/tests/cases/conformance/types/intersection/intersectionOfUnionNarrowing.ts b/tests/cases/conformance/types/intersection/intersectionOfUnionNarrowing.ts new file mode 100644 index 0000000000000..0f67b66bff1f2 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionOfUnionNarrowing.ts @@ -0,0 +1,16 @@ +// @strict: true + +interface X { + a?: { aProp: string }; + b?: { bProp: string }; +} +type AorB = { a: object; b: undefined } | { a: undefined; b: object }; + +declare const q: X & AorB; + +if (q.a !== undefined) { + q.a.aProp; +} else { + // q.b is previously incorrectly inferred as potentially undefined + q.b.bProp; +}