Type guards in || operator
• In the right operand of a || operation, the type of a variable or parameter is narrowed by any type guard in the left operand when false, provided the right operand contains no assignments to the variable or parameter.
This commit is contained in:
parent
11912e8fde
commit
33cdc2f876
3 changed files with 366 additions and 0 deletions
|
@ -0,0 +1,96 @@
|
|||
//// [typeGuardsInRightOperandOfOrOrOperator.ts]
|
||||
// In the right operand of a || operation,
|
||||
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
|
||||
// provided the right operand contains no assignments to the variable or parameter.
|
||||
function foo(x: number | string) {
|
||||
return typeof x !== "string" || x.length === 10; // string
|
||||
}
|
||||
function foo2(x: number | string) {
|
||||
// modify x in right hand operand
|
||||
return typeof x !== "string" || ((x = 10) || x); // string | number
|
||||
}
|
||||
function foo3(x: number | string) {
|
||||
// modify x in right hand operand with string type itself
|
||||
return typeof x !== "string" || ((x = "hello") || x); // string | number
|
||||
}
|
||||
function foo4(x: number | string | boolean) {
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| typeof x === "number" // number | boolean
|
||||
|| x; // boolean
|
||||
}
|
||||
function foo5(x: number | string | boolean) {
|
||||
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
|
||||
var b: number | boolean;
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| ((b = x) || (typeof x === "number" // number | boolean
|
||||
|| x)); // boolean
|
||||
}
|
||||
function foo6(x: number | string | boolean) {
|
||||
// Mixing typeguard
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| (typeof x !== "number" // number | boolean
|
||||
? x // boolean
|
||||
: x === 10) // number
|
||||
}
|
||||
function foo7(x: number | string | boolean) {
|
||||
var y: number| boolean | string;
|
||||
var z: number| boolean | string;
|
||||
// Mixing typeguard narrowing
|
||||
// Assigning value to x deep inside another guard stops narrowing of type too
|
||||
return typeof x === "string"
|
||||
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
|
||||
|| (typeof x === "number"
|
||||
// change value of x
|
||||
? (x = 10 && x.toString()) // number | boolean | string
|
||||
// do not change value
|
||||
: (y = x && x.toString()))); // number | boolean | string
|
||||
}
|
||||
function foo8(x: number | string) {
|
||||
// Mixing typeguard
|
||||
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
|
||||
return typeof x === "string"
|
||||
|| (x = 10) // change x - number| string
|
||||
|| (typeof x === "number"
|
||||
? x // number
|
||||
: x.length); // string
|
||||
}
|
||||
|
||||
//// [typeGuardsInRightOperandOfOrOrOperator.js]
|
||||
// In the right operand of a || operation,
|
||||
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
|
||||
// provided the right operand contains no assignments to the variable or parameter.
|
||||
function foo(x) {
|
||||
return typeof x !== "string" || x.length === 10; // string
|
||||
}
|
||||
function foo2(x) {
|
||||
// modify x in right hand operand
|
||||
return typeof x !== "string" || ((x = 10) || x); // string | number
|
||||
}
|
||||
function foo3(x) {
|
||||
// modify x in right hand operand with string type itself
|
||||
return typeof x !== "string" || ((x = "hello") || x); // string | number
|
||||
}
|
||||
function foo4(x) {
|
||||
return typeof x === "string" || typeof x === "number" || x; // boolean
|
||||
}
|
||||
function foo5(x) {
|
||||
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
|
||||
var b;
|
||||
return typeof x === "string" || ((b = x) || (typeof x === "number" || x)); // boolean
|
||||
}
|
||||
function foo6(x) {
|
||||
// Mixing typeguard
|
||||
return typeof x === "string" || (typeof x !== "number" ? x : x === 10); // number
|
||||
}
|
||||
function foo7(x) {
|
||||
var y;
|
||||
var z;
|
||||
// Mixing typeguard narrowing
|
||||
// Assigning value to x deep inside another guard stops narrowing of type too
|
||||
return typeof x === "string" || ((z = x) || (typeof x === "number" ? (x = 10 && x.toString()) : (y = x && x.toString()))); // number | boolean | string
|
||||
}
|
||||
function foo8(x) {
|
||||
// Mixing typeguard
|
||||
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
|
||||
return typeof x === "string" || (x = 10) || (typeof x === "number" ? x : x.length); // string
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts ===
|
||||
// In the right operand of a || operation,
|
||||
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
|
||||
// provided the right operand contains no assignments to the variable or parameter.
|
||||
function foo(x: number | string) {
|
||||
>foo : (x: string | number) => boolean
|
||||
>x : string | number
|
||||
|
||||
return typeof x !== "string" || x.length === 10; // string
|
||||
>typeof x !== "string" || x.length === 10 : boolean
|
||||
>typeof x !== "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>x.length === 10 : boolean
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
function foo2(x: number | string) {
|
||||
>foo2 : (x: string | number) => string | number | boolean
|
||||
>x : string | number
|
||||
|
||||
// modify x in right hand operand
|
||||
return typeof x !== "string" || ((x = 10) || x); // string | number
|
||||
>typeof x !== "string" || ((x = 10) || x) : string | number | boolean
|
||||
>typeof x !== "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>((x = 10) || x) : string | number
|
||||
>(x = 10) || x : string | number
|
||||
>(x = 10) : number
|
||||
>x = 10 : number
|
||||
>x : string | number
|
||||
>x : string | number
|
||||
}
|
||||
function foo3(x: number | string) {
|
||||
>foo3 : (x: string | number) => string | number | boolean
|
||||
>x : string | number
|
||||
|
||||
// modify x in right hand operand with string type itself
|
||||
return typeof x !== "string" || ((x = "hello") || x); // string | number
|
||||
>typeof x !== "string" || ((x = "hello") || x) : string | number | boolean
|
||||
>typeof x !== "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
>((x = "hello") || x) : string | number
|
||||
>(x = "hello") || x : string | number
|
||||
>(x = "hello") : string
|
||||
>x = "hello" : string
|
||||
>x : string | number
|
||||
>x : string | number
|
||||
}
|
||||
function foo4(x: number | string | boolean) {
|
||||
>foo4 : (x: string | number | boolean) => boolean
|
||||
>x : string | number | boolean
|
||||
|
||||
return typeof x === "string" // string | number | boolean
|
||||
>typeof x === "string" // string | number | boolean || typeof x === "number" // number | boolean || x : boolean
|
||||
>typeof x === "string" // string | number | boolean || typeof x === "number" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number | boolean
|
||||
|
||||
|| typeof x === "number" // number | boolean
|
||||
>typeof x === "number" : boolean
|
||||
>typeof x : string
|
||||
>x : number | boolean
|
||||
|
||||
|| x; // boolean
|
||||
>x : boolean
|
||||
}
|
||||
function foo5(x: number | string | boolean) {
|
||||
>foo5 : (x: string | number | boolean) => number | boolean
|
||||
>x : string | number | boolean
|
||||
|
||||
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
|
||||
var b: number | boolean;
|
||||
>b : number | boolean
|
||||
|
||||
return typeof x === "string" // string | number | boolean
|
||||
>typeof x === "string" // string | number | boolean || ((b = x) || (typeof x === "number" // number | boolean || x)) : number | boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number | boolean
|
||||
|
||||
|| ((b = x) || (typeof x === "number" // number | boolean
|
||||
>((b = x) || (typeof x === "number" // number | boolean || x)) : number | boolean
|
||||
>(b = x) || (typeof x === "number" // number | boolean || x) : number | boolean
|
||||
>(b = x) : number | boolean
|
||||
>b = x : number | boolean
|
||||
>b : number | boolean
|
||||
>x : number | boolean
|
||||
>(typeof x === "number" // number | boolean || x) : boolean
|
||||
>typeof x === "number" // number | boolean || x : boolean
|
||||
>typeof x === "number" : boolean
|
||||
>typeof x : string
|
||||
>x : number | boolean
|
||||
|
||||
|| x)); // boolean
|
||||
>x : boolean
|
||||
}
|
||||
function foo6(x: number | string | boolean) {
|
||||
>foo6 : (x: string | number | boolean) => boolean
|
||||
>x : string | number | boolean
|
||||
|
||||
// Mixing typeguard
|
||||
return typeof x === "string" // string | number | boolean
|
||||
>typeof x === "string" // string | number | boolean || (typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number | boolean
|
||||
|
||||
|| (typeof x !== "number" // number | boolean
|
||||
>(typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
|
||||
>typeof x !== "number" // number | boolean ? x // boolean : x === 10 : boolean
|
||||
>typeof x !== "number" : boolean
|
||||
>typeof x : string
|
||||
>x : number | boolean
|
||||
|
||||
? x // boolean
|
||||
>x : boolean
|
||||
|
||||
: x === 10) // number
|
||||
>x === 10 : boolean
|
||||
>x : number
|
||||
}
|
||||
function foo7(x: number | string | boolean) {
|
||||
>foo7 : (x: string | number | boolean) => string | number | boolean
|
||||
>x : string | number | boolean
|
||||
|
||||
var y: number| boolean | string;
|
||||
>y : string | number | boolean
|
||||
|
||||
var z: number| boolean | string;
|
||||
>z : string | number | boolean
|
||||
|
||||
// Mixing typeguard narrowing
|
||||
// Assigning value to x deep inside another guard stops narrowing of type too
|
||||
return typeof x === "string"
|
||||
>typeof x === "string" || ((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string | number | boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number | boolean
|
||||
|
||||
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
|
||||
>((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string | number | boolean
|
||||
>(z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string | number | boolean
|
||||
>(z = x) : string | number | boolean
|
||||
>z = x : string | number | boolean
|
||||
>z : string | number | boolean
|
||||
>x : string | number | boolean
|
||||
|
||||
|| (typeof x === "number"
|
||||
>(typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string
|
||||
>typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()) : string
|
||||
>typeof x === "number" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number | boolean
|
||||
|
||||
// change value of x
|
||||
? (x = 10 && x.toString()) // number | boolean | string
|
||||
>(x = 10 && x.toString()) : string
|
||||
>x = 10 && x.toString() : string
|
||||
>x : string | number | boolean
|
||||
>10 && x.toString() : string
|
||||
>x.toString() : string
|
||||
>x.toString : () => string
|
||||
>x : string | number | boolean
|
||||
>toString : () => string
|
||||
|
||||
// do not change value
|
||||
: (y = x && x.toString()))); // number | boolean | string
|
||||
>(y = x && x.toString()) : string
|
||||
>y = x && x.toString() : string
|
||||
>y : string | number | boolean
|
||||
>x && x.toString() : string
|
||||
>x : string | number | boolean
|
||||
>x.toString() : string
|
||||
>x.toString : () => string
|
||||
>x : string | number | boolean
|
||||
>toString : () => string
|
||||
}
|
||||
function foo8(x: number | string) {
|
||||
>foo8 : (x: string | number) => number | boolean
|
||||
>x : string | number
|
||||
|
||||
// Mixing typeguard
|
||||
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
|
||||
return typeof x === "string"
|
||||
>typeof x === "string" || (x = 10) // change x - number| string || (typeof x === "number" ? x // number : x.length) : number | boolean
|
||||
>typeof x === "string" || (x = 10) : number | boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
|
||||
|| (x = 10) // change x - number| string
|
||||
>(x = 10) : number
|
||||
>x = 10 : number
|
||||
>x : string | number
|
||||
|
||||
|| (typeof x === "number"
|
||||
>(typeof x === "number" ? x // number : x.length) : number
|
||||
>typeof x === "number" ? x // number : x.length : number
|
||||
>typeof x === "number" : boolean
|
||||
>typeof x : string
|
||||
>x : string | number
|
||||
|
||||
? x // number
|
||||
>x : number
|
||||
|
||||
: x.length); // string
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// In the right operand of a || operation,
|
||||
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
|
||||
// provided the right operand contains no assignments to the variable or parameter.
|
||||
function foo(x: number | string) {
|
||||
return typeof x !== "string" || x.length === 10; // string
|
||||
}
|
||||
function foo2(x: number | string) {
|
||||
// modify x in right hand operand
|
||||
return typeof x !== "string" || ((x = 10) || x); // string | number
|
||||
}
|
||||
function foo3(x: number | string) {
|
||||
// modify x in right hand operand with string type itself
|
||||
return typeof x !== "string" || ((x = "hello") || x); // string | number
|
||||
}
|
||||
function foo4(x: number | string | boolean) {
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| typeof x === "number" // number | boolean
|
||||
|| x; // boolean
|
||||
}
|
||||
function foo5(x: number | string | boolean) {
|
||||
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
|
||||
var b: number | boolean;
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| ((b = x) || (typeof x === "number" // number | boolean
|
||||
|| x)); // boolean
|
||||
}
|
||||
function foo6(x: number | string | boolean) {
|
||||
// Mixing typeguard
|
||||
return typeof x === "string" // string | number | boolean
|
||||
|| (typeof x !== "number" // number | boolean
|
||||
? x // boolean
|
||||
: x === 10) // number
|
||||
}
|
||||
function foo7(x: number | string | boolean) {
|
||||
var y: number| boolean | string;
|
||||
var z: number| boolean | string;
|
||||
// Mixing typeguard narrowing
|
||||
// Assigning value to x deep inside another guard stops narrowing of type too
|
||||
return typeof x === "string"
|
||||
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
|
||||
|| (typeof x === "number"
|
||||
// change value of x
|
||||
? (x = 10 && x.toString()) // number | boolean | string
|
||||
// do not change value
|
||||
: (y = x && x.toString()))); // number | boolean | string
|
||||
}
|
||||
function foo8(x: number | string) {
|
||||
// Mixing typeguard
|
||||
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
|
||||
return typeof x === "string"
|
||||
|| (x = 10) // change x - number| string
|
||||
|| (typeof x === "number"
|
||||
? x // number
|
||||
: x.length); // string
|
||||
}
|
Loading…
Reference in a new issue