=== 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 >"string" : string >x.length === 10 : boolean >x.length : number >x : string >length : number >10 : 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 >"string" : string >((x = 10) || x) : string | number >(x = 10) || x : string | number >(x = 10) : number >x = 10 : number >x : string | number >10 : 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 >"string" : string >((x = "hello") || x) : string | number >(x = "hello") || x : string | number >(x = "hello") : string >x = "hello" : string >x : string | number >"hello" : string >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 >"string" : string || typeof x === "number" // number | boolean >typeof x === "number" : boolean >typeof x : string >x : number | boolean >"number" : string || 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 >"string" : string || ((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 >"number" : string || 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 >"string" : string || (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 >"number" : string ? x // boolean >x : boolean : x === 10) // number >x === 10 : boolean >x : number >10 : 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 >"string" : string || ((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 >"number" : string // 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 >10 : number >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 >"string" : string || (x = 10) // change x - number| string >(x = 10) : number >x = 10 : number >x : string | number >10 : 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 >"number" : string ? x // number >x : number : x.length); // string >x.length : number >x : string >length : number }