diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 11ac767e5aeb3..0536d79ad7bde 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18713,7 +18713,8 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") // Before normalization: if `source` is type an object type, and `target` is primitive, // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { - if (isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) { + if (relation === comparableRelation && !(originalTarget.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(originalTarget, originalSource, relation) || + isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) { return Ternary.True; } if (reportErrors) { diff --git a/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.symbols b/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.symbols new file mode 100644 index 0000000000000..31aef77dba10e --- /dev/null +++ b/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.symbols @@ -0,0 +1,88 @@ +=== tests/cases/compiler/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts === +// strictNullChecks: false + +// repro #49643 + +interface A {} +>A : Symbol(A, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 0, 0)) + +interface B {} +>B : Symbol(B, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 4, 14)) + +declare let opts: +>opts : Symbol(opts, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 7, 11)) + + | { objectRef?: undefined; getObjectRef: () => any } +>objectRef : Symbol(objectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 6)) +>getObjectRef : Symbol(getObjectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 29)) + + | { objectRef: A | B; getObjectRef?: undefined }; +>objectRef : Symbol(objectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 6)) +>A : Symbol(A, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 0, 0)) +>B : Symbol(B, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 4, 14)) +>getObjectRef : Symbol(getObjectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 24)) + +opts.objectRef || opts.getObjectRef(); +>opts.objectRef : Symbol(objectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 6), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 6)) +>opts : Symbol(opts, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 7, 11)) +>objectRef : Symbol(objectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 6), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 6)) +>opts.getObjectRef : Symbol(getObjectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 29), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 24)) +>opts : Symbol(opts, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 7, 11)) +>getObjectRef : Symbol(getObjectRef, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 8, 29), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 9, 24)) + +// repro #49643 issuecomment-1174455723 + +interface X { +>X : Symbol(X, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 11, 38)) + + foo: string; +>foo : Symbol(X.foo, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 15, 13)) +} + +interface Y { +>Y : Symbol(Y, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 17, 1)) + + baz: number; +>baz : Symbol(Y.baz, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 19, 13)) +} + +interface A2 { +>A2 : Symbol(A2, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 21, 1)) + + result: unknown; +>result : Symbol(A2.result, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 23, 14)) + + error: undefined; +>error : Symbol(A2.error, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 24, 20)) +} + +interface B2 { +>B2 : Symbol(B2, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 26, 1)) + + error: X | Y; +>error : Symbol(B2.error, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 28, 14)) +>X : Symbol(X, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 11, 38)) +>Y : Symbol(Y, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 17, 1)) +} + +const testMethod = (m: A2 | B2) => { +>testMethod : Symbol(testMethod, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 32, 5)) +>m : Symbol(m, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 32, 20)) +>A2 : Symbol(A2, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 21, 1)) +>B2 : Symbol(B2, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 26, 1)) + + if (m.error) { +>m.error : Symbol(error, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 24, 20), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 28, 14)) +>m : Symbol(m, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 32, 20)) +>error : Symbol(error, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 24, 20), Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 28, 14)) + + m; // should be A2 | B2 +>m : Symbol(m, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 32, 20)) + + } else { + m; // should be A2 | B2 +>m : Symbol(m, Decl(discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts, 32, 20)) + } +} + + diff --git a/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.types b/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.types new file mode 100644 index 0000000000000..20e677643efa3 --- /dev/null +++ b/tests/baselines/reference/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.types @@ -0,0 +1,74 @@ +=== tests/cases/compiler/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts === +// strictNullChecks: false + +// repro #49643 + +interface A {} +interface B {} + +declare let opts: +>opts : { objectRef?: undefined; getObjectRef: () => any; } | { objectRef: A | B; getObjectRef?: undefined; } + + | { objectRef?: undefined; getObjectRef: () => any } +>objectRef : undefined +>getObjectRef : () => any + + | { objectRef: A | B; getObjectRef?: undefined }; +>objectRef : A | B +>getObjectRef : undefined + +opts.objectRef || opts.getObjectRef(); +>opts.objectRef || opts.getObjectRef() : any +>opts.objectRef : A | B +>opts : { objectRef?: undefined; getObjectRef: () => any; } | { objectRef: A | B; getObjectRef?: undefined; } +>objectRef : A | B +>opts.getObjectRef() : any +>opts.getObjectRef : () => any +>opts : { objectRef?: undefined; getObjectRef: () => any; } | { objectRef: A | B; getObjectRef?: undefined; } +>getObjectRef : () => any + +// repro #49643 issuecomment-1174455723 + +interface X { + foo: string; +>foo : string +} + +interface Y { + baz: number; +>baz : number +} + +interface A2 { + result: unknown; +>result : unknown + + error: undefined; +>error : undefined +} + +interface B2 { + error: X | Y; +>error : X | Y +} + +const testMethod = (m: A2 | B2) => { +>testMethod : (m: A2 | B2) => void +>(m: A2 | B2) => { if (m.error) { m; // should be A2 | B2 } else { m; // should be A2 | B2 }} : (m: A2 | B2) => void +>m : A2 | B2 + + if (m.error) { +>m.error : X | Y +>m : A2 | B2 +>error : X | Y + + m; // should be A2 | B2 +>m : A2 | B2 + + } else { + m; // should be A2 | B2 +>m : A2 | B2 + } +} + + diff --git a/tests/cases/compiler/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts b/tests/cases/compiler/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts new file mode 100644 index 0000000000000..054ba9c683a83 --- /dev/null +++ b/tests/cases/compiler/discriminatingUnionWithUnionPropertyAgainstUndefinedWithoutStrictNullChecks.ts @@ -0,0 +1,41 @@ +// @noEmit: true +// strictNullChecks: false + +// repro #49643 + +interface A {} +interface B {} + +declare let opts: + | { objectRef?: undefined; getObjectRef: () => any } + | { objectRef: A | B; getObjectRef?: undefined }; + +opts.objectRef || opts.getObjectRef(); + +// repro #49643 issuecomment-1174455723 + +interface X { + foo: string; +} + +interface Y { + baz: number; +} + +interface A2 { + result: unknown; + error: undefined; +} + +interface B2 { + error: X | Y; +} + +const testMethod = (m: A2 | B2) => { + if (m.error) { + m; // should be A2 | B2 + } else { + m; // should be A2 | B2 + } +} +