Skip to content

Commit 110b059

Browse files
authored
Fix GH-32798: Allow == null to narrow unknown to null | undefined (#45853)
* Fix GH-32798 * add assume true * Address Gabby comments * Address Gabby comments by adding Else branch
1 parent 5a9e1af commit 110b059

File tree

6 files changed

+133
-14
lines changed

6 files changed

+133
-14
lines changed

src/compiler/checker.ts

+3
Original file line numberDiff line numberDiff line change
@@ -23913,6 +23913,9 @@ namespace ts {
2391323913
assumeTrue = !assumeTrue;
2391423914
}
2391523915
const valueType = getTypeOfExpression(value);
23916+
if (assumeTrue && (type.flags & TypeFlags.Unknown) && (operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken) && (valueType.flags & TypeFlags.Null)) {
23917+
return getUnionType([nullType, undefinedType]);
23918+
}
2391623919
if ((type.flags & TypeFlags.Unknown) && assumeTrue && (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) {
2391723920
if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) {
2391823921
return valueType;

tests/baselines/reference/narrowByEquality.errors.txt

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
tests/cases/compiler/narrowByEquality.ts(53,15): error TS2322: Type 'string | number' is not assignable to type 'number'.
1+
tests/cases/compiler/narrowByEquality.ts(54,15): error TS2322: Type 'string | number' is not assignable to type 'number'.
22
Type 'string' is not assignable to type 'number'.
3-
tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | number' is not assignable to type 'number'.
3+
tests/cases/compiler/narrowByEquality.ts(55,9): error TS2322: Type 'string | number' is not assignable to type 'number'.
44
Type 'string' is not assignable to type 'number'.
55

66

@@ -9,6 +9,7 @@ tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | num
99
declare let n: number;
1010
declare let s: string;
1111
declare let b: boolean;
12+
declare let xUnknown: unknown;
1213

1314
if (x == n) {
1415
x;
@@ -68,4 +69,18 @@ tests/cases/compiler/narrowByEquality.ts(54,9): error TS2322: Type 'string | num
6869
}
6970
return 0;
7071
}
72+
73+
// From issue #32798
74+
if (xUnknown == null) {
75+
xUnknown;
76+
} else {
77+
xUnknown
78+
}
79+
80+
if (xUnknown != null) {
81+
xUnknown;
82+
} else {
83+
xUnknown;
84+
}
85+
7186

tests/baselines/reference/narrowByEquality.js

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ declare let x: number | string | boolean
33
declare let n: number;
44
declare let s: string;
55
declare let b: boolean;
6+
declare let xUnknown: unknown;
67

78
if (x == n) {
89
x;
@@ -56,6 +57,20 @@ function test(level: number | string):number {
5657
}
5758
return 0;
5859
}
60+
61+
// From issue #32798
62+
if (xUnknown == null) {
63+
xUnknown;
64+
} else {
65+
xUnknown
66+
}
67+
68+
if (xUnknown != null) {
69+
xUnknown;
70+
} else {
71+
xUnknown;
72+
}
73+
5974

6075

6176
//// [narrowByEquality.js]
@@ -99,3 +114,16 @@ function test(level) {
99114
}
100115
return 0;
101116
}
117+
// From issue #32798
118+
if (xUnknown == null) {
119+
xUnknown;
120+
}
121+
else {
122+
xUnknown;
123+
}
124+
if (xUnknown != null) {
125+
xUnknown;
126+
}
127+
else {
128+
xUnknown;
129+
}

tests/baselines/reference/narrowByEquality.symbols

+39-12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ declare let s: string;
1111
declare let b: boolean;
1212
>b : Symbol(b, Decl(narrowByEquality.ts, 3, 11))
1313

14+
declare let xUnknown: unknown;
15+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
16+
1417
if (x == n) {
1518
>x : Symbol(x, Decl(narrowByEquality.ts, 0, 11))
1619
>n : Symbol(n, Decl(narrowByEquality.ts, 1, 11))
@@ -71,43 +74,67 @@ if (x == false) {
7174
}
7275

7376
declare let xAndObj: number | string | boolean | object
74-
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11))
77+
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11))
7578

7679
if (xAndObj == {}) {
77-
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11))
80+
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11))
7881

7982
xAndObj;
80-
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11))
83+
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11))
8184
}
8285

8386
if (x == xAndObj) {
8487
>x : Symbol(x, Decl(narrowByEquality.ts, 0, 11))
85-
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11))
88+
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11))
8689

8790
x;
8891
>x : Symbol(x, Decl(narrowByEquality.ts, 0, 11))
8992

9093
xAndObj;
91-
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 37, 11))
94+
>xAndObj : Symbol(xAndObj, Decl(narrowByEquality.ts, 38, 11))
9295
}
9396

9497
// Repro from #24991
9598

9699
function test(level: number | string):number {
97-
>test : Symbol(test, Decl(narrowByEquality.ts, 46, 1))
98-
>level : Symbol(level, Decl(narrowByEquality.ts, 50, 14))
100+
>test : Symbol(test, Decl(narrowByEquality.ts, 47, 1))
101+
>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14))
99102

100103
if (level == +level) {
101-
>level : Symbol(level, Decl(narrowByEquality.ts, 50, 14))
102-
>level : Symbol(level, Decl(narrowByEquality.ts, 50, 14))
104+
>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14))
105+
>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14))
103106

104107
const q2: number = level; // error
105-
>q2 : Symbol(q2, Decl(narrowByEquality.ts, 52, 13))
106-
>level : Symbol(level, Decl(narrowByEquality.ts, 50, 14))
108+
>q2 : Symbol(q2, Decl(narrowByEquality.ts, 53, 13))
109+
>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14))
107110

108111
return level;
109-
>level : Symbol(level, Decl(narrowByEquality.ts, 50, 14))
112+
>level : Symbol(level, Decl(narrowByEquality.ts, 51, 14))
110113
}
111114
return 0;
112115
}
113116

117+
// From issue #32798
118+
if (xUnknown == null) {
119+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
120+
121+
xUnknown;
122+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
123+
124+
} else {
125+
xUnknown
126+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
127+
}
128+
129+
if (xUnknown != null) {
130+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
131+
132+
xUnknown;
133+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
134+
135+
} else {
136+
xUnknown;
137+
>xUnknown : Symbol(xUnknown, Decl(narrowByEquality.ts, 4, 11))
138+
}
139+
140+

tests/baselines/reference/narrowByEquality.types

+31
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ declare let s: string;
1111
declare let b: boolean;
1212
>b : boolean
1313

14+
declare let xUnknown: unknown;
15+
>xUnknown : unknown
16+
1417
if (x == n) {
1518
>x == n : boolean
1619
>x : string | number | boolean
@@ -130,3 +133,31 @@ function test(level: number | string):number {
130133
>0 : 0
131134
}
132135

136+
// From issue #32798
137+
if (xUnknown == null) {
138+
>xUnknown == null : boolean
139+
>xUnknown : unknown
140+
>null : null
141+
142+
xUnknown;
143+
>xUnknown : null | undefined
144+
145+
} else {
146+
xUnknown
147+
>xUnknown : unknown
148+
}
149+
150+
if (xUnknown != null) {
151+
>xUnknown != null : boolean
152+
>xUnknown : unknown
153+
>null : null
154+
155+
xUnknown;
156+
>xUnknown : unknown
157+
158+
} else {
159+
xUnknown;
160+
>xUnknown : null | undefined
161+
}
162+
163+

tests/cases/compiler/narrowByEquality.ts

+15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ declare let x: number | string | boolean
44
declare let n: number;
55
declare let s: string;
66
declare let b: boolean;
7+
declare let xUnknown: unknown;
78

89
if (x == n) {
910
x;
@@ -57,3 +58,17 @@ function test(level: number | string):number {
5758
}
5859
return 0;
5960
}
61+
62+
// From issue #32798
63+
if (xUnknown == null) {
64+
xUnknown;
65+
} else {
66+
xUnknown
67+
}
68+
69+
if (xUnknown != null) {
70+
xUnknown;
71+
} else {
72+
xUnknown;
73+
}
74+

0 commit comments

Comments
 (0)