Chain RHS narrowing and truthiness narrowing in assignment expression narrowing (#31348)

This commit is contained in:
Wesley Wigham
2019-05-13 14:41:33 -07:00
committed by GitHub
parent 546028156e
commit f140dfc30b
9 changed files with 194 additions and 15 deletions

View File

@@ -16773,7 +16773,7 @@ namespace ts {
function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
switch (expr.operatorToken.kind) {
case SyntaxKind.EqualsToken:
return narrowTypeByTruthiness(type, expr.left, assumeTrue);
return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue);
case SyntaxKind.EqualsEqualsToken:
case SyntaxKind.ExclamationEqualsToken:
case SyntaxKind.EqualsEqualsEqualsToken:

View File

@@ -0,0 +1,36 @@
//// [controlFlowForCompoundAssignmentToThisMember.ts]
class DatasourceCommandWidgetElement {
_commandBased: boolean;
_commandElement: unknown;
commandElement: unknown;
constructor(target: unknown) {
if (target instanceof DatasourceCommandWidgetElement) {
this._commandBased = true;
this._commandElement = target.commandElement;
} else {
this._commandBased = false;
}
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
this._commandElement = target.commandElement;
}
}
}
//// [controlFlowForCompoundAssignmentToThisMember.js]
var DatasourceCommandWidgetElement = /** @class */ (function () {
function DatasourceCommandWidgetElement(target) {
if (target instanceof DatasourceCommandWidgetElement) {
this._commandBased = true;
this._commandElement = target.commandElement;
}
else {
this._commandBased = false;
}
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
this._commandElement = target.commandElement;
}
}
return DatasourceCommandWidgetElement;
}());

View File

@@ -0,0 +1,57 @@
=== tests/cases/compiler/controlFlowForCompoundAssignmentToThisMember.ts ===
class DatasourceCommandWidgetElement {
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
_commandBased: boolean;
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
_commandElement: unknown;
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
commandElement: unknown;
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
constructor(target: unknown) {
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
if (target instanceof DatasourceCommandWidgetElement) {
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
this._commandBased = true;
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
this._commandElement = target.commandElement;
>this._commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
>target.commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
} else {
this._commandBased = false;
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
}
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
>this._commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
>_commandBased : Symbol(DatasourceCommandWidgetElement._commandBased, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 38))
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
>DatasourceCommandWidgetElement : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
this._commandElement = target.commandElement;
>this._commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
>this : Symbol(DatasourceCommandWidgetElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 0, 0))
>_commandElement : Symbol(DatasourceCommandWidgetElement._commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 1, 27))
>target.commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
>target : Symbol(target, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 5, 16))
>commandElement : Symbol(DatasourceCommandWidgetElement.commandElement, Decl(controlFlowForCompoundAssignmentToThisMember.ts, 2, 29))
}
}
}

View File

@@ -0,0 +1,67 @@
=== tests/cases/compiler/controlFlowForCompoundAssignmentToThisMember.ts ===
class DatasourceCommandWidgetElement {
>DatasourceCommandWidgetElement : DatasourceCommandWidgetElement
_commandBased: boolean;
>_commandBased : boolean
_commandElement: unknown;
>_commandElement : unknown
commandElement: unknown;
>commandElement : unknown
constructor(target: unknown) {
>target : unknown
if (target instanceof DatasourceCommandWidgetElement) {
>target instanceof DatasourceCommandWidgetElement : boolean
>target : unknown
>DatasourceCommandWidgetElement : typeof DatasourceCommandWidgetElement
this._commandBased = true;
>this._commandBased = true : true
>this._commandBased : boolean
>this : this
>_commandBased : boolean
>true : true
this._commandElement = target.commandElement;
>this._commandElement = target.commandElement : unknown
>this._commandElement : unknown
>this : this
>_commandElement : unknown
>target.commandElement : unknown
>target : DatasourceCommandWidgetElement
>commandElement : unknown
} else {
this._commandBased = false;
>this._commandBased = false : false
>this._commandBased : boolean
>this : this
>_commandBased : boolean
>false : false
}
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
>this._commandBased = (target instanceof DatasourceCommandWidgetElement) : boolean
>this._commandBased : boolean
>this : this
>_commandBased : boolean
>(target instanceof DatasourceCommandWidgetElement) : boolean
>target instanceof DatasourceCommandWidgetElement : boolean
>target : unknown
>DatasourceCommandWidgetElement : typeof DatasourceCommandWidgetElement
this._commandElement = target.commandElement;
>this._commandElement = target.commandElement : unknown
>this._commandElement : unknown
>this : this
>_commandElement : unknown
>target.commandElement : unknown
>target : DatasourceCommandWidgetElement
>commandElement : unknown
}
}
}

View File

@@ -111,7 +111,7 @@ function f5() {
>x : string
y; // string | undefined
>y : string | undefined
>y : string
}
else {
x; // string | undefined

View File

@@ -211,11 +211,11 @@ function foo8(x: number | string | boolean) {
>typeof x === "boolean" ? x // boolean : x == 10 : boolean
>typeof x === "boolean" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"boolean" : "boolean"
? x // boolean
>x : boolean
>x : true
: x == 10)); // boolean
>x == 10 : boolean
@@ -286,7 +286,7 @@ function foo10(x: number | string | boolean) {
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"number" : "number"
&& x.toString()); // x is number
@@ -326,7 +326,7 @@ function foo11(x: number | string | boolean) {
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"number" : "number"
&& (x = 10) // assignment to x
@@ -379,7 +379,7 @@ function foo12(x: number | string | boolean) {
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"number" : "number"
&& x); // x is number

View File

@@ -102,11 +102,11 @@ function foo5(x: number | string | boolean) {
>typeof x !== "number" // number | boolean && x : boolean
>typeof x !== "number" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"number" : "number"
&& x)); // boolean
>x : boolean
>x : true
}
function foo6(x: number | string | boolean) {
>foo6 : (x: string | number | boolean) => boolean
@@ -167,7 +167,7 @@ function foo7(x: number | string | boolean) {
>typeof x === "number" // change value of x ? ((x = 10) && x.toString()) // x is number // do not change value : ((y = x) && x.toString()) : string
>typeof x === "number" : boolean
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : number | boolean
>x : number | true
>"number" : "number"
// change value of x
@@ -187,13 +187,13 @@ function foo7(x: number | string | boolean) {
: ((y = x) && x.toString()))); // x is boolean
>((y = x) && x.toString()) : string
>(y = x) && x.toString() : string
>(y = x) : boolean
>y = x : boolean
>(y = x) : true
>y = x : true
>y : string | number | boolean
>x : boolean
>x : true
>x.toString() : string
>x.toString : () => string
>x : boolean
>x : true
>toString : () => string
}

View File

@@ -194,7 +194,7 @@ function foo7(x: number | string | boolean) {
>x : boolean
>x.toString() : string
>x.toString : () => string
>x : boolean
>x : true
>toString : () => string
}

View File

@@ -0,0 +1,19 @@
class DatasourceCommandWidgetElement {
_commandBased: boolean;
_commandElement: unknown;
commandElement: unknown;
constructor(target: unknown) {
if (target instanceof DatasourceCommandWidgetElement) {
this._commandBased = true;
this._commandElement = target.commandElement;
} else {
this._commandBased = false;
}
if (this._commandBased = (target instanceof DatasourceCommandWidgetElement)) {
this._commandElement = target.commandElement;
}
}
}