diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30d9ad9021327..5e1a078408428 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23895,6 +23895,9 @@ namespace ts { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); + if (assumeTrue && (type.flags & TypeFlags.Unknown) && (operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken) && (valueType.flags & TypeFlags.Null)) { + return getUnionType([nullType, undefinedType]); + } if ((type.flags & TypeFlags.Unknown) && assumeTrue && (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) { if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { return valueType; diff --git a/tests/baselines/reference/narrowByEquality.errors.txt b/tests/baselines/reference/narrowByEquality.errors.txt index b391c4a07a1c4..15610d6d1d49a 100644 --- a/tests/baselines/reference/narrowByEquality.errors.txt +++ b/tests/baselines/reference/narrowByEquality.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/narrowByEquality.ts(53,15): error TS2322: Type 'string | number' is not assignable to type 'number'. +tests/cases/compiler/narrowByEquality.ts(54,15): error TS2322: Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | number' is not assignable to type 'number'. +tests/cases/compiler/narrowByEquality.ts(55,9): error TS2322: Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. @@ -9,6 +9,7 @@ tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | num declare let n: number; declare let s: string; declare let b: boolean; + declare let xUnknown: unknown; if (x == n) { x; @@ -68,4 +69,18 @@ tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | num } return 0; } + + // From issue #32798 + if (xUnknown == null) { + xUnknown; + } else { + xUnknown + } + + if (xUnknown != null) { + xUnknown; + } else { + xUnknown; + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowByEquality.js b/tests/baselines/reference/narrowByEquality.js index a843040db7795..ec8bb8bdbb563 100644 --- a/tests/baselines/reference/narrowByEquality.js +++ b/tests/baselines/reference/narrowByEquality.js @@ -3,6 +3,7 @@ declare let x: number | string | boolean declare let n: number; declare let s: string; declare let b: boolean; +declare let xUnknown: unknown; if (x == n) { x; @@ -56,6 +57,20 @@ function test(level: number | string):number { } return 0; } + +// From issue #32798 +if (xUnknown == null) { + xUnknown; +} else { + xUnknown +} + +if (xUnknown != null) { + xUnknown; +} else { + xUnknown; +} + //// [narrowByEquality.js] @@ -99,3 +114,16 @@ function test(level) { } return 0; } +// From issue #32798 +if (xUnknown == null) { + xUnknown; +} +else { + xUnknown; +} +if (xUnknown != null) { + xUnknown; +} +else { + xUnknown; +} diff --git a/tests/baselines/reference/narrowByEquality.symbols b/tests/baselines/reference/narrowByEquality.symbols index 02e2ae138d98e..50c8d626f8828 100644 --- a/tests/baselines/reference/narrowByEquality.symbols +++ b/tests/baselines/reference/narrowByEquality.symbols @@ -11,6 +11,9 @@ declare let s: string; declare let b: boolean; >b : Symbol(b, Decl(narrowByEquality.ts, 3, 11)) +declare let xUnknown: unknown; +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) + if (x == n) { >x : Symbol(x, Decl(narrowByEquality.ts, 0, 11)) >n : Symbol(n, Decl(narrowByEquality.ts, 1, 11)) @@ -71,43 +74,67 @@ if (x == false) { } declare let xAndObj: number | string | boolean | object ->xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11)) +>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11)) if (xAndObj == {}) { ->xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11)) +>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11)) xAndObj; ->xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11)) +>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11)) } if (x == xAndObj) { >x : Symbol(x, Decl(narrowByEquality.ts, 0, 11)) ->xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11)) +>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11)) x; >x : Symbol(x, Decl(narrowByEquality.ts, 0, 11)) xAndObj; ->xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11)) +>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11)) } // Repro from #24991 function test(level: number | string):number { ->test : Symbol(test, Decl(narrowByEquality.ts, 46, 1)) ->level : Symbol(level, Decl(narrowByEquality.ts, 50, 14)) +>test : Symbol(test, Decl(narrowByEquality.ts, 47, 1)) +>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14)) if (level == +level) { ->level : Symbol(level, Decl(narrowByEquality.ts, 50, 14)) ->level : Symbol(level, Decl(narrowByEquality.ts, 50, 14)) +>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14)) +>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14)) const q2: number = level; // error ->q2 : Symbol(q2, Decl(narrowByEquality.ts, 52, 13)) ->level : Symbol(level, Decl(narrowByEquality.ts, 50, 14)) +>q2 : Symbol(q2, Decl(narrowByEquality.ts, 53, 13)) +>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14)) return level; ->level : Symbol(level, Decl(narrowByEquality.ts, 50, 14)) +>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14)) } return 0; } +// From issue #32798 +if (xUnknown == null) { +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) + + xUnknown; +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) + +} else { + xUnknown +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) +} + +if (xUnknown != null) { +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) + + xUnknown; +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) + +} else { + xUnknown; +>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11)) +} + + diff --git a/tests/baselines/reference/narrowByEquality.types b/tests/baselines/reference/narrowByEquality.types index 0dfb3bb8e116d..4f5c8a5195840 100644 --- a/tests/baselines/reference/narrowByEquality.types +++ b/tests/baselines/reference/narrowByEquality.types @@ -11,6 +11,9 @@ declare let s: string; declare let b: boolean; >b : boolean +declare let xUnknown: unknown; +>xUnknown : unknown + if (x == n) { >x == n : boolean >x : string | number | boolean @@ -130,3 +133,31 @@ function test(level: number | string):number { >0 : 0 } +// From issue #32798 +if (xUnknown == null) { +>xUnknown == null : boolean +>xUnknown : unknown +>null : null + + xUnknown; +>xUnknown : null | undefined + +} else { + xUnknown +>xUnknown : unknown +} + +if (xUnknown != null) { +>xUnknown != null : boolean +>xUnknown : unknown +>null : null + + xUnknown; +>xUnknown : unknown + +} else { + xUnknown; +>xUnknown : null | undefined +} + + diff --git a/tests/cases/compiler/narrowByEquality.ts b/tests/cases/compiler/narrowByEquality.ts index a0ebe09a9a9a7..bd2a053e9c795 100644 --- a/tests/cases/compiler/narrowByEquality.ts +++ b/tests/cases/compiler/narrowByEquality.ts @@ -4,6 +4,7 @@ declare let x: number | string | boolean declare let n: number; declare let s: string; declare let b: boolean; +declare let xUnknown: unknown; if (x == n) { x; @@ -57,3 +58,17 @@ function test(level: number | string):number { } return 0; } + +// From issue #32798 +if (xUnknown == null) { + xUnknown; +} else { + xUnknown +} + +if (xUnknown != null) { + xUnknown; +} else { + xUnknown; +} +