Skip to content

Commit f140dfc

Browse files
authored
Chain RHS narrowing and truthiness narrowing in assignment expression narrowing (#31348)
1 parent 5460281 commit f140dfc

9 files changed

+194
-15
lines changed

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16773,7 +16773,7 @@ namespace ts {
1677316773
function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
1677416774
switch (expr.operatorToken.kind) {
1677516775
case SyntaxKind.EqualsToken:
16776-
return narrowTypeByTruthiness(type, expr.left, assumeTrue);
16776+
return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue);
1677716777
case SyntaxKind.EqualsEqualsToken:
1677816778
case SyntaxKind.ExclamationEqualsToken:
1677916779
case SyntaxKind.EqualsEqualsEqualsToken:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [controlFlowForCompoundAssignmentToThisMember.ts]
2+
class DatasourceCommandWidgetElement {
3+
_commandBased: boolean;
4+
_commandElement: unknown;
5+
commandElement: unknown;
6+
7+
constructor(target: unknown) {
8+
if (target instanceof DatasourceCommandWidgetElement) {
9+
this._commandBased = true;
10+
this._commandElement = target.commandElement;
11+
} else {
12+
this._commandBased = false;
13+
}
14+
15+
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
16+
this._commandElement = target.commandElement;
17+
}
18+
}
19+
}
20+
21+
//// [controlFlowForCompoundAssignmentToThisMember.js]
22+
var DatasourceCommandWidgetElement = /** @class */ (function () {
23+
function DatasourceCommandWidgetElement(target) {
24+
if (target instanceof DatasourceCommandWidgetElement) {
25+
this._commandBased = true;
26+
this._commandElement = target.commandElement;
27+
}
28+
else {
29+
this._commandBased = false;
30+
}
31+
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
32+
this._commandElement = target.commandElement;
33+
}
34+
}
35+
return DatasourceCommandWidgetElement;
36+
}());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
=== tests/cases/compiler/controlFlowForCompoundAssignmentToThisMember.ts ===
2+
class DatasourceCommandWidgetElement {
3+
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
4+
5+
_commandBased: boolean;
6+
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
7+
8+
_commandElement: unknown;
9+
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
10+
11+
commandElement: unknown;
12+
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
13+
14+
constructor(target: unknown) {
15+
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
16+
17+
if (target instanceof DatasourceCommandWidgetElement) {
18+
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
19+
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
20+
21+
this._commandBased = true;
22+
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
23+
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
24+
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
25+
26+
this._commandElement = target.commandElement;
27+
>this._commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
28+
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
29+
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
30+
>target.commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
31+
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
32+
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
33+
34+
} else {
35+
this._commandBased = false;
36+
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
37+
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
38+
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
39+
}
40+
41+
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
42+
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
43+
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
44+
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
45+
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
46+
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
47+
48+
this._commandElement = target.commandElement;
49+
>this._commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
50+
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
51+
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
52+
>target.commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
53+
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
54+
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
55+
}
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/compiler/controlFlowForCompoundAssignmentToThisMember.ts ===
2+
class DatasourceCommandWidgetElement {
3+
>DatasourceCommandWidgetElement : DatasourceCommandWidgetElement
4+
5+
_commandBased: boolean;
6+
>_commandBased : boolean
7+
8+
_commandElement: unknown;
9+
>_commandElement : unknown
10+
11+
commandElement: unknown;
12+
>commandElement : unknown
13+
14+
constructor(target: unknown) {
15+
>target : unknown
16+
17+
if (target instanceof DatasourceCommandWidgetElement) {
18+
>target instanceof DatasourceCommandWidgetElement : boolean
19+
>target : unknown
20+
>DatasourceCommandWidgetElement : typeof DatasourceCommandWidgetElement
21+
22+
this._commandBased = true;
23+
>this._commandBased = true : true
24+
>this._commandBased : boolean
25+
>this : this
26+
>_commandBased : boolean
27+
>true : true
28+
29+
this._commandElement = target.commandElement;
30+
>this._commandElement = target.commandElement : unknown
31+
>this._commandElement : unknown
32+
>this : this
33+
>_commandElement : unknown
34+
>target.commandElement : unknown
35+
>target : DatasourceCommandWidgetElement
36+
>commandElement : unknown
37+
38+
} else {
39+
this._commandBased = false;
40+
>this._commandBased = false : false
41+
>this._commandBased : boolean
42+
>this : this
43+
>_commandBased : boolean
44+
>false : false
45+
}
46+
47+
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
48+
>this._commandBased = (target instanceof DatasourceCommandWidgetElement) : boolean
49+
>this._commandBased : boolean
50+
>this : this
51+
>_commandBased : boolean
52+
>(target instanceof DatasourceCommandWidgetElement) : boolean
53+
>target instanceof DatasourceCommandWidgetElement : boolean
54+
>target : unknown
55+
>DatasourceCommandWidgetElement : typeof DatasourceCommandWidgetElement
56+
57+
this._commandElement = target.commandElement;
58+
>this._commandElement = target.commandElement : unknown
59+
>this._commandElement : unknown
60+
>this : this
61+
>_commandElement : unknown
62+
>target.commandElement : unknown
63+
>target : DatasourceCommandWidgetElement
64+
>commandElement : unknown
65+
}
66+
}
67+
}

tests/baselines/reference/controlFlowTruthiness.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function f5() {
111111
>x : string
112112

113113
y; // string | undefined
114-
>y : string | undefined
114+
>y : string
115115
}
116116
else {
117117
x; // string | undefined

tests/baselines/reference/typeGuardsInConditionalExpression.types

+5-5
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,11 @@ function foo8(x: number | string | boolean) {
211211
>typeof x === "boolean" ? x // boolean : x == 10 : boolean
212212
>typeof x === "boolean" : boolean
213213
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
214-
>x : number | boolean
214+
>x : number | true
215215
>"boolean" : "boolean"
216216

217217
? x // boolean
218-
>x : boolean
218+
>x : true
219219

220220
: x == 10)); // boolean
221221
>x == 10 : boolean
@@ -286,7 +286,7 @@ function foo10(x: number | string | boolean) {
286286
&& typeof x === "number"
287287
>typeof x === "number" : boolean
288288
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
289-
>x : number | boolean
289+
>x : number | true
290290
>"number" : "number"
291291

292292
&& x.toString()); // x is number
@@ -326,7 +326,7 @@ function foo11(x: number | string | boolean) {
326326
&& typeof x === "number"
327327
>typeof x === "number" : boolean
328328
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
329-
>x : number | boolean
329+
>x : number | true
330330
>"number" : "number"
331331

332332
&& (x = 10) // assignment to x
@@ -379,7 +379,7 @@ function foo12(x: number | string | boolean) {
379379
&& typeof x === "number"
380380
>typeof x === "number" : boolean
381381
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
382-
>x : number | boolean
382+
>x : number | true
383383
>"number" : "number"
384384

385385
&& x); // x is number

tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types

+7-7
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ function foo5(x: number | string | boolean) {
102102
>typeof x !== "number" // number | boolean && x : boolean
103103
>typeof x !== "number" : boolean
104104
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
105-
>x : number | boolean
105+
>x : number | true
106106
>"number" : "number"
107107

108108
&& x)); // boolean
109-
>x : boolean
109+
>x : true
110110
}
111111
function foo6(x: number | string | boolean) {
112112
>foo6 : (x: string | number | boolean) => boolean
@@ -167,7 +167,7 @@ function foo7(x: number | string | boolean) {
167167
>typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString()) : string
168168
>typeof x === "number" : boolean
169169
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
170-
>x : number | boolean
170+
>x : number | true
171171
>"number" : "number"
172172

173173
// change value of x
@@ -187,13 +187,13 @@ function foo7(x: number | string | boolean) {
187187
: ((y = x) && x.toString()))); // x is boolean
188188
>((y = x) && x.toString()) : string
189189
>(y = x) && x.toString() : string
190-
>(y = x) : boolean
191-
>y = x : boolean
190+
>(y = x) : true
191+
>y = x : true
192192
>y : string | number | boolean
193-
>x : boolean
193+
>x : true
194194
>x.toString() : string
195195
>x.toString : () => string
196-
>x : boolean
196+
>x : true
197197
>toString : () => string
198198
}
199199

tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ function foo7(x: number | string | boolean) {
194194
>x : boolean
195195
>x.toString() : string
196196
>x.toString : () => string
197-
>x : boolean
197+
>x : true
198198
>toString : () => string
199199
}
200200

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
class DatasourceCommandWidgetElement {
3+
_commandBased: boolean;
4+
_commandElement: unknown;
5+
commandElement: unknown;
6+
7+
constructor(target: unknown) {
8+
if (target instanceof DatasourceCommandWidgetElement) {
9+
this._commandBased = true;
10+
this._commandElement = target.commandElement;
11+
} else {
12+
this._commandBased = false;
13+
}
14+
15+
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
16+
this._commandElement = target.commandElement;
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)