Fixed a regression with discriminating unions based on a union property against undefined with strictNullChecks: false (#49648)

* Fixed a regression with discriminating unions based on a union property against `undefined` with `strictNullChecks: false`

* Add additional test case from the issue comment
This commit is contained in:
Mateusz Burzyński
2022-11-07 21:17:59 +01:00
committed by GitHub
parent 7b0df1ff99
commit a329210166
4 changed files with 205 additions and 1 deletions

View File

@@ -18986,7 +18986,8 @@ namespace ts {
// 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) {

View File

@@ -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))
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}