From 7c1b28f2cbb0327e46411db789edf04cb961685e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 8 Jun 2016 15:55:08 -0700 Subject: [PATCH 1/3] Allow primitive type guards with typeof on right Previously, only type guards of the form `typeof x === 'string'` were allowed. Now you can write `'string' === typeof x`. --- src/compiler/binder.ts | 16 +++++++++++++++- src/compiler/checker.ts | 17 +++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 8c48d984b7853..bfc9b07697b16 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -612,7 +612,7 @@ namespace ts { if (isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) { return true; } - if (expr.left.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((expr.left).expression) && expr.right.kind === SyntaxKind.StringLiteral) { + if (isTypeOfNarrowingBinaryExpression(expr)) { return true; } return false; @@ -624,6 +624,20 @@ namespace ts { return false; } + function isTypeOfNarrowingBinaryExpression(expr: BinaryExpression) { + let typeOf: Expression; + if (expr.left.kind === SyntaxKind.StringLiteral) { + typeOf = expr.right; + } + else if (expr.right.kind === SyntaxKind.StringLiteral) { + typeOf = expr.left; + } + else { + typeOf = undefined;; + } + return typeOf && typeOf.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((typeOf).expression); + } + function createBranchLabel(): FlowLabel { return { flags: FlowFlags.BranchLabel, diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 650bc488b0e1d..dbc2c920dbb2c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7864,7 +7864,8 @@ namespace ts { if (isNullOrUndefinedLiteral(expr.right)) { return narrowTypeByNullCheck(type, expr, assumeTrue); } - if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral) { + if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral || + expr.left.kind === SyntaxKind.StringLiteral && expr.right.kind === SyntaxKind.TypeOfExpression) { return narrowTypeByTypeof(type, expr, assumeTrue); } break; @@ -7897,12 +7898,12 @@ namespace ts { function narrowTypeByTypeof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { // We have '==', '!=', '====', or !==' operator with 'typeof xxx' on the left // and string literal on the right - const left = expr.left; - const right = expr.right; - if (!isMatchingReference(reference, left.expression)) { + const typeOf = (expr.left.kind === SyntaxKind.TypeOfExpression ? expr.left : expr.right); + const literal = (expr.right.kind === SyntaxKind.StringLiteral ? expr.right : expr.left); + if (!isMatchingReference(reference, typeOf.expression)) { // For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the // narrowed type of 'y' to its declared type. - if (containsMatchingReference(reference, left.expression)) { + if (containsMatchingReference(reference, typeOf.expression)) { return declaredType; } return type; @@ -7915,14 +7916,14 @@ namespace ts { // We narrow a non-union type to an exact primitive type if the non-union type // is a supertype of that primtive type. For example, type 'any' can be narrowed // to one of the primitive types. - const targetType = getProperty(typeofTypesByName, right.text); + const targetType = getProperty(typeofTypesByName, literal.text); if (targetType && isTypeSubtypeOf(targetType, type)) { return targetType; } } const facts = assumeTrue ? - getProperty(typeofEQFacts, right.text) || TypeFacts.TypeofEQHostObject : - getProperty(typeofNEFacts, right.text) || TypeFacts.TypeofNEHostObject; + getProperty(typeofEQFacts, literal.text) || TypeFacts.TypeofEQHostObject : + getProperty(typeofNEFacts, literal.text) || TypeFacts.TypeofNEHostObject; return getTypeWithFacts(type, facts); } From 11377f9fd342dc21012e9cff1d60d0a2226f30e6 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 8 Jun 2016 15:56:25 -0700 Subject: [PATCH 2/3] Primitive type guards are now order independent --- ...typeGuardOfFormTypeOfIsOrderIndependent.js | 71 ++++++++++++++ ...uardOfFormTypeOfIsOrderIndependent.symbols | 75 +++++++++++++++ ...eGuardOfFormTypeOfIsOrderIndependent.types | 95 +++++++++++++++++++ ...typeGuardOfFormTypeOfIsOrderIndependent.ts | 34 +++++++ 4 files changed, 275 insertions(+) create mode 100644 tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js create mode 100644 tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js new file mode 100644 index 0000000000000..5ea7932e89a9d --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js @@ -0,0 +1,71 @@ +//// [typeGuardOfFormTypeOfIsOrderIndependent.ts] +var strOrNum: string | number; +var strOrBool: string | boolean; +var strOrFunc: string | (() => void); +var numOrBool: number | boolean +var str: string; +var num: number; +var bool: boolean; +var func: () => void; + +if ("string" === typeof strOrNum) { +// if (typeof strOrNum === "string") { + str = strOrNum; +} +else { + num = strOrNum; +} +if ("function" === typeof strOrFunc) { + func = strOrFunc; +} +else { + str = strOrFunc; +} +if ("number" === typeof numOrBool) { + num = numOrBool; +} +else { + bool = numOrBool; +} +if ("boolean" === typeof strOrBool) { + bool = strOrBool; +} +else { + str = strOrBool; +} + + +//// [typeGuardOfFormTypeOfIsOrderIndependent.js] +var strOrNum; +var strOrBool; +var strOrFunc; +var numOrBool; +var str; +var num; +var bool; +var func; +if ("string" === typeof strOrNum) { + // if (typeof strOrNum === "string") { + str = strOrNum; +} +else { + num = strOrNum; +} +if ("function" === typeof strOrFunc) { + func = strOrFunc; +} +else { + str = strOrFunc; +} +if ("number" === typeof numOrBool) { + num = numOrBool; +} +else { + bool = numOrBool; +} +if ("boolean" === typeof strOrBool) { + bool = strOrBool; +} +else { + str = strOrBool; +} diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols new file mode 100644 index 0000000000000..d75774eba455b --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols @@ -0,0 +1,75 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts === +var strOrNum: string | number; +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) + +var strOrBool: string | boolean; +>strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 1, 3)) + +var strOrFunc: string | (() => void); +>strOrFunc : Symbol(strOrFunc, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 2, 3)) + +var numOrBool: number | boolean +>numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 3, 3)) + +var str: string; +>str : Symbol(str, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 4, 3)) + +var num: number; +>num : Symbol(num, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 5, 3)) + +var bool: boolean; +>bool : Symbol(bool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 6, 3)) + +var func: () => void; +>func : Symbol(func, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 7, 3)) + +if ("string" === typeof strOrNum) { +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) + +// if (typeof strOrNum === "string") { + str = strOrNum; +>str : Symbol(str, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 4, 3)) +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) +} +else { + num = strOrNum; +>num : Symbol(num, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 5, 3)) +>strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) +} +if ("function" === typeof strOrFunc) { +>strOrFunc : Symbol(strOrFunc, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 2, 3)) + + func = strOrFunc; +>func : Symbol(func, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 7, 3)) +>strOrFunc : Symbol(strOrFunc, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 2, 3)) +} +else { + str = strOrFunc; +>str : Symbol(str, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 4, 3)) +>strOrFunc : Symbol(strOrFunc, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 2, 3)) +} +if ("number" === typeof numOrBool) { +>numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 3, 3)) + + num = numOrBool; +>num : Symbol(num, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 5, 3)) +>numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 3, 3)) +} +else { + bool = numOrBool; +>bool : Symbol(bool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 6, 3)) +>numOrBool : Symbol(numOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 3, 3)) +} +if ("boolean" === typeof strOrBool) { +>strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 1, 3)) + + bool = strOrBool; +>bool : Symbol(bool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 6, 3)) +>strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 1, 3)) +} +else { + str = strOrBool; +>str : Symbol(str, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 4, 3)) +>strOrBool : Symbol(strOrBool, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 1, 3)) +} + diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types new file mode 100644 index 0000000000000..592d147f38691 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types @@ -0,0 +1,95 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts === +var strOrNum: string | number; +>strOrNum : string | number + +var strOrBool: string | boolean; +>strOrBool : string | boolean + +var strOrFunc: string | (() => void); +>strOrFunc : string | (() => void) + +var numOrBool: number | boolean +>numOrBool : number | boolean + +var str: string; +>str : string + +var num: number; +>num : number + +var bool: boolean; +>bool : boolean + +var func: () => void; +>func : () => void + +if ("string" === typeof strOrNum) { +>"string" === typeof strOrNum : boolean +>"string" : string +>typeof strOrNum : string +>strOrNum : string | number + +// if (typeof strOrNum === "string") { + str = strOrNum; +>str = strOrNum : string +>str : string +>strOrNum : string +} +else { + num = strOrNum; +>num = strOrNum : number +>num : number +>strOrNum : number +} +if ("function" === typeof strOrFunc) { +>"function" === typeof strOrFunc : boolean +>"function" : string +>typeof strOrFunc : string +>strOrFunc : string | (() => void) + + func = strOrFunc; +>func = strOrFunc : () => void +>func : () => void +>strOrFunc : () => void +} +else { + str = strOrFunc; +>str = strOrFunc : string +>str : string +>strOrFunc : string +} +if ("number" === typeof numOrBool) { +>"number" === typeof numOrBool : boolean +>"number" : string +>typeof numOrBool : string +>numOrBool : number | boolean + + num = numOrBool; +>num = numOrBool : number +>num : number +>numOrBool : number +} +else { + bool = numOrBool; +>bool = numOrBool : boolean +>bool : boolean +>numOrBool : boolean +} +if ("boolean" === typeof strOrBool) { +>"boolean" === typeof strOrBool : boolean +>"boolean" : string +>typeof strOrBool : string +>strOrBool : string | boolean + + bool = strOrBool; +>bool = strOrBool : boolean +>bool : boolean +>strOrBool : boolean +} +else { + str = strOrBool; +>str = strOrBool : string +>str : string +>strOrBool : string +} + diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts new file mode 100644 index 0000000000000..79fcf49e24572 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts @@ -0,0 +1,34 @@ +var strOrNum: string | number; +var strOrBool: string | boolean; +var strOrFunc: string | (() => void); +var numOrBool: number | boolean +var str: string; +var num: number; +var bool: boolean; +var func: () => void; + +if ("string" === typeof strOrNum) { +// if (typeof strOrNum === "string") { + str = strOrNum; +} +else { + num = strOrNum; +} +if ("function" === typeof strOrFunc) { + func = strOrFunc; +} +else { + str = strOrFunc; +} +if ("number" === typeof numOrBool) { + num = numOrBool; +} +else { + bool = numOrBool; +} +if ("boolean" === typeof strOrBool) { + bool = strOrBool; +} +else { + str = strOrBool; +} From a1e4b31d160b11ac4b579b34892ad8e05b64bc42 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 9 Jun 2016 15:48:35 -0700 Subject: [PATCH 3/3] Allow null/undefined guard with null/undefined on left Also add a test with baselines. --- src/compiler/binder.ts | 5 ++- src/compiler/checker.ts | 10 +++-- ...lOrUndefinedTypeGuardIsOrderIndependent.js | 30 +++++++++++++ ...definedTypeGuardIsOrderIndependent.symbols | 34 +++++++++++++++ ...UndefinedTypeGuardIsOrderIndependent.types | 43 +++++++++++++++++++ ...typeGuardOfFormTypeOfIsOrderIndependent.js | 2 - ...uardOfFormTypeOfIsOrderIndependent.symbols | 1 - ...eGuardOfFormTypeOfIsOrderIndependent.types | 1 - ...lOrUndefinedTypeGuardIsOrderIndependent.ts | 14 ++++++ ...typeGuardOfFormTypeOfIsOrderIndependent.ts | 1 - 10 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.js create mode 100644 tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.symbols create mode 100644 tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.types create mode 100644 tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index bfc9b07697b16..96213801264bc 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -609,7 +609,8 @@ namespace ts { case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - if (isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) { + if ((isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) || + (isNarrowingExpression(expr.right) && (expr.left.kind === SyntaxKind.NullKeyword || expr.left.kind === SyntaxKind.Identifier))) { return true; } if (isTypeOfNarrowingBinaryExpression(expr)) { @@ -633,7 +634,7 @@ namespace ts { typeOf = expr.left; } else { - typeOf = undefined;; + typeOf = undefined; } return typeOf && typeOf.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((typeOf).expression); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dbc2c920dbb2c..281bac299146b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7861,7 +7861,7 @@ namespace ts { case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - if (isNullOrUndefinedLiteral(expr.right)) { + if (isNullOrUndefinedLiteral(expr.left) || isNullOrUndefinedLiteral(expr.right)) { return narrowTypeByNullCheck(type, expr, assumeTrue); } if (expr.left.kind === SyntaxKind.TypeOfExpression && expr.right.kind === SyntaxKind.StringLiteral || @@ -7878,18 +7878,20 @@ namespace ts { } function narrowTypeByNullCheck(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { - // We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' on the right + // We have '==', '!=', '===', or '!==' operator with 'null' or 'undefined' on one side const operator = expr.operatorToken.kind; + const nullLike = isNullOrUndefinedLiteral(expr.left) ? expr.left : expr.right; + const narrowed = isNullOrUndefinedLiteral(expr.left) ? expr.right : expr.left; if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { assumeTrue = !assumeTrue; } - if (!strictNullChecks || !isMatchingReference(reference, expr.left)) { + if (!strictNullChecks || !isMatchingReference(reference, narrowed)) { return type; } const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; const facts = doubleEquals ? assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : - expr.right.kind === SyntaxKind.NullKeyword ? + nullLike.kind === SyntaxKind.NullKeyword ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; return getTypeWithFacts(type, facts); diff --git a/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.js b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.js new file mode 100644 index 0000000000000..f62bd2a3f118a --- /dev/null +++ b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.js @@ -0,0 +1,30 @@ +//// [nullOrUndefinedTypeGuardIsOrderIndependent.ts] +function test(strOrNull: string | null, strOrUndefined: string | undefined) { + var str: string = "original"; + var nil: null; + if (null === strOrNull) { + nil = strOrNull; + } + else { + str = strOrNull; + } + if (undefined !== strOrUndefined) { + str = strOrUndefined; + } +} + + +//// [nullOrUndefinedTypeGuardIsOrderIndependent.js] +function test(strOrNull, strOrUndefined) { + var str = "original"; + var nil; + if (null === strOrNull) { + nil = strOrNull; + } + else { + str = strOrNull; + } + if (undefined !== strOrUndefined) { + str = strOrUndefined; + } +} diff --git a/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.symbols b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.symbols new file mode 100644 index 0000000000000..bb1d18432893b --- /dev/null +++ b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.symbols @@ -0,0 +1,34 @@ +=== tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts === +function test(strOrNull: string | null, strOrUndefined: string | undefined) { +>test : Symbol(test, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 0)) +>strOrNull : Symbol(strOrNull, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 14)) +>strOrUndefined : Symbol(strOrUndefined, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 39)) + + var str: string = "original"; +>str : Symbol(str, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 1, 7)) + + var nil: null; +>nil : Symbol(nil, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 2, 7)) + + if (null === strOrNull) { +>strOrNull : Symbol(strOrNull, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 14)) + + nil = strOrNull; +>nil : Symbol(nil, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 2, 7)) +>strOrNull : Symbol(strOrNull, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 14)) + } + else { + str = strOrNull; +>str : Symbol(str, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 1, 7)) +>strOrNull : Symbol(strOrNull, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 14)) + } + if (undefined !== strOrUndefined) { +>undefined : Symbol(undefined) +>strOrUndefined : Symbol(strOrUndefined, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 39)) + + str = strOrUndefined; +>str : Symbol(str, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 1, 7)) +>strOrUndefined : Symbol(strOrUndefined, Decl(nullOrUndefinedTypeGuardIsOrderIndependent.ts, 0, 39)) + } +} + diff --git a/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.types b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.types new file mode 100644 index 0000000000000..f599366e66e62 --- /dev/null +++ b/tests/baselines/reference/nullOrUndefinedTypeGuardIsOrderIndependent.types @@ -0,0 +1,43 @@ +=== tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts === +function test(strOrNull: string | null, strOrUndefined: string | undefined) { +>test : (strOrNull: string | null, strOrUndefined: string | undefined) => void +>strOrNull : string | null +>null : null +>strOrUndefined : string | undefined + + var str: string = "original"; +>str : string +>"original" : string + + var nil: null; +>nil : null +>null : null + + if (null === strOrNull) { +>null === strOrNull : boolean +>null : null +>strOrNull : string | null + + nil = strOrNull; +>nil = strOrNull : null +>nil : null +>strOrNull : null + } + else { + str = strOrNull; +>str = strOrNull : string +>str : string +>strOrNull : string + } + if (undefined !== strOrUndefined) { +>undefined !== strOrUndefined : boolean +>undefined : undefined +>strOrUndefined : string | undefined + + str = strOrUndefined; +>str = strOrUndefined : string +>str : string +>strOrUndefined : string + } +} + diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js index 5ea7932e89a9d..7d9a1651f08d7 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.js @@ -9,7 +9,6 @@ var bool: boolean; var func: () => void; if ("string" === typeof strOrNum) { -// if (typeof strOrNum === "string") { str = strOrNum; } else { @@ -45,7 +44,6 @@ var num; var bool; var func; if ("string" === typeof strOrNum) { - // if (typeof strOrNum === "string") { str = strOrNum; } else { diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols index d75774eba455b..f33908631a408 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.symbols @@ -26,7 +26,6 @@ var func: () => void; if ("string" === typeof strOrNum) { >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) -// if (typeof strOrNum === "string") { str = strOrNum; >str : Symbol(str, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 4, 3)) >strOrNum : Symbol(strOrNum, Decl(typeGuardOfFormTypeOfIsOrderIndependent.ts, 0, 3)) diff --git a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types index 592d147f38691..2d91abb9613ac 100644 --- a/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types +++ b/tests/baselines/reference/typeGuardOfFormTypeOfIsOrderIndependent.types @@ -29,7 +29,6 @@ if ("string" === typeof strOrNum) { >typeof strOrNum : string >strOrNum : string | number -// if (typeof strOrNum === "string") { str = strOrNum; >str = strOrNum : string >str : string diff --git a/tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts b/tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts new file mode 100644 index 0000000000000..2da52406609ec --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/nullOrUndefinedTypeGuardIsOrderIndependent.ts @@ -0,0 +1,14 @@ +// @strictNullChecks: true +function test(strOrNull: string | null, strOrUndefined: string | undefined) { + var str: string = "original"; + var nil: null; + if (null === strOrNull) { + nil = strOrNull; + } + else { + str = strOrNull; + } + if (undefined !== strOrUndefined) { + str = strOrUndefined; + } +} diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts index 79fcf49e24572..b7a5caf41daf5 100644 --- a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormTypeOfIsOrderIndependent.ts @@ -8,7 +8,6 @@ var bool: boolean; var func: () => void; if ("string" === typeof strOrNum) { -// if (typeof strOrNum === "string") { str = strOrNum; } else {