From 9e43183884825fa3b17359ac167fdaa6aacb2530 Mon Sep 17 00:00:00 2001 From: Jack Williams Date: Wed, 23 May 2018 01:03:04 +0100 Subject: [PATCH] Add fall-through test and correct comment about implied type --- src/compiler/checker.ts | 19 +- .../reference/narrowingByTypeofInSwitch.js | 45 ++ .../narrowingByTypeofInSwitch.symbols | 415 ++++++++++-------- .../reference/narrowingByTypeofInSwitch.types | 62 +++ .../compiler/narrowingByTypeofInSwitch.ts | 24 + 5 files changed, 375 insertions(+), 190 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ab2cc1f3b8519..1629717ff2861 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13594,10 +13594,10 @@ namespace ts { // } // // The implied type of the first clause number | string. - // The implied type of the second clause is string (but this doesn't get used). + // The implied type of the second clause is never, but this does not get just because it includes a default case. // The implied type of the third clause is boolean (number has already be caught). if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) { - let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => typeofTypesByName.get(text) || neverType)), switchFacts); + let impliedType = getTypeWithFacts(getUnionType((clauseWitnesses).map(text => typeofTypesByName.get(text) || neverType)), switchFacts); if (impliedType.flags & TypeFlags.Union) { impliedType = getAssignmentReducedType(impliedType as UnionType, getBaseConstraintOfType(type) || type); } @@ -19027,17 +19027,20 @@ namespace ts { if (hasDefault) { // Value is not equal to any types after the active clause. for (let i = end; i < witnesses.length; i++) { - facts |= typeofNEFacts.get(witnesses[i]) || TypeFacts.TypeofNEHostObject; + const witness = witnesses[i]; + facts |= (witness && typeofNEFacts.get(witness)) || TypeFacts.TypeofNEHostObject; } // Remove inequalities for types that appear in the // active clause because they appear before other // types collected so far. for (let i = start; i < end; i++) { - facts &= ~(typeofNEFacts.get(witnesses[i]) || 0); + const witness = witnesses[i]; + facts &= ~((witness && typeofNEFacts.get(witness)) || 0); } // Add inequalities for types before the active clause unconditionally. for (let i = 0; i < start; i++) { - facts |= typeofNEFacts.get(witnesses[i]) || TypeFacts.TypeofNEHostObject; + const witness = witnesses[i]; + facts |= (witness && typeofNEFacts.get(witness)) || TypeFacts.TypeofNEHostObject; } } // When in an active clause without default the set of @@ -19045,12 +19048,14 @@ namespace ts { else { // Add equalities for all types in the active clause. for (let i = start; i < end; i++) { - facts |= typeofEQFacts.get(witnesses[i]) || TypeFacts.TypeofEQHostObject; + const witness = witnesses[i]; + facts |= (witness && typeofEQFacts.get(witness)) || TypeFacts.TypeofEQHostObject; } // Remove equalities for types that appear before the // active clause. for (let i = 0; i < start; i++) { - facts &= ~(typeofEQFacts.get(witnesses[i]) || 0); + const witness = witnesses[i]; + facts &= ~((witness && typeofEQFacts.get(witness)) || 0); } } return facts; diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.js b/tests/baselines/reference/narrowingByTypeofInSwitch.js index 2cf4b9027c2c8..95ec120a85d2d 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.js +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.js @@ -35,6 +35,14 @@ function assertAll(x: Basic) { return x; } +function assertStringOrNumber(x: string | number) { + return x; +} + +function assertBooleanOrObject(x: boolean | object) { + return x; +} + type Basic = number | boolean | string | symbol | object | Function | undefined; function testUnion(x: Basic) { @@ -186,6 +194,22 @@ function switchOrderingWithDefault(x: string | number | boolean) { case 'number': return assertNever(x); } } + +function fallThroughTest(x: string | number | boolean | object) { + switch (typeof x) { + case 'number': + assertNumber(x) + case 'string': + assertStringOrNumber(x) + break; + default: + assertObject(x); + case 'number': + case 'boolean': + assertBooleanOrObject(x); + break; + } +} //// [narrowingByTypeofInSwitch.js] @@ -216,6 +240,12 @@ function assertUndefined(x) { function assertAll(x) { return x; } +function assertStringOrNumber(x) { + return x; +} +function assertBooleanOrObject(x) { + return x; +} function testUnion(x) { switch (typeof x) { case 'number': @@ -425,3 +455,18 @@ function switchOrderingWithDefault(x) { case 'number': return assertNever(x); } } +function fallThroughTest(x) { + switch (typeof x) { + case 'number': + assertNumber(x); + case 'string': + assertStringOrNumber(x); + break; + default: + assertObject(x); + case 'number': + case 'boolean': + assertBooleanOrObject(x); + break; + } +} diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.symbols b/tests/baselines/reference/narrowingByTypeofInSwitch.symbols index 2d1bd06baba98..b451b39ac7c22 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.symbols +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.symbols @@ -67,476 +67,525 @@ function assertUndefined(x: undefined) { function assertAll(x: Basic) { >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) >x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 32, 19)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) return x; >x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 32, 19)) } +function assertStringOrNumber(x: string | number) { +>assertStringOrNumber : Symbol(assertStringOrNumber, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 36, 30)) + + return x; +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 36, 30)) +} + +function assertBooleanOrObject(x: boolean | object) { +>assertBooleanOrObject : Symbol(assertBooleanOrObject, Decl(narrowingByTypeofInSwitch.ts, 38, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 40, 31)) + + return x; +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 40, 31)) +} + type Basic = number | boolean | string | symbol | object | Function | undefined; ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) function testUnion(x: Basic) { ->testUnion : Symbol(testUnion, Decl(narrowingByTypeofInSwitch.ts, 36, 80)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>testUnion : Symbol(testUnion, Decl(narrowingByTypeofInSwitch.ts, 44, 80)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'function': assertFunction(x); return; >assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'object': assertObject(x); return; >assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'string': assertString(x); return; >assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) case 'undefined': assertUndefined(x); return; >assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) } assertNever(x); >assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 38, 19)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19)) } function testExtendsUnion(x: T) { ->testExtendsUnion : Symbol(testExtendsUnion, Decl(narrowingByTypeofInSwitch.ts, 49, 1)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 51, 26)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 51, 26)) +>testExtendsUnion : Symbol(testExtendsUnion, Decl(narrowingByTypeofInSwitch.ts, 57, 1)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 59, 26)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 59, 26)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'function': assertAll(x); return; >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'object': assertAll(x); return; >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'string': assertString(x); return; >assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) case 'undefined': assertUndefined(x); return; >assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) } assertAll(x); >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 51, 43)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43)) } function testAny(x: any) { ->testAny : Symbol(testAny, Decl(narrowingByTypeofInSwitch.ts, 62, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>testAny : Symbol(testAny, Decl(narrowingByTypeofInSwitch.ts, 70, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'function': assertFunction(x); return; >assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'object': assertObject(x); return; >assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'string': assertString(x); return; >assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) case 'undefined': assertUndefined(x); return; >assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) } assertAll(x); // is any >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 64, 17)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 72, 17)) } function a1(x: string | object | undefined) { ->a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 75, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 77, 12)) +>a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 83, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 85, 12)) return x; ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 77, 12)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 85, 12)) } function testUnionExplicitDefault(x: Basic) { ->testUnionExplicitDefault : Symbol(testUnionExplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 79, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>testUnionExplicitDefault : Symbol(testUnionExplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 87, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) case 'function': assertFunction(x); return; >assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) default: a1(x); return; ->a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 75, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 81, 34)) +>a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 83, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 89, 34)) } } function testUnionImplicitDefault(x: Basic) { ->testUnionImplicitDefault : Symbol(testUnionImplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 89, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>testUnionImplicitDefault : Symbol(testUnionImplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 97, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) case 'function': assertFunction(x); return; >assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) } return a1(x); ->a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 75, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 91, 34)) +>a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 83, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34)) } function testExtendsExplicitDefault(x: T) { ->testExtendsExplicitDefault : Symbol(testExtendsExplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 99, 1)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 101, 36)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 101, 36)) +>testExtendsExplicitDefault : Symbol(testExtendsExplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 107, 1)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 109, 36)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 109, 36)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) case 'function': assertAll(x); return; >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) default: assertAll(x); return; >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 101, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53)) } } function testExtendsImplicitDefault(x: T) { ->testExtendsImplicitDefault : Symbol(testExtendsImplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 110, 1)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 112, 36)) ->Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 112, 36)) +>testExtendsImplicitDefault : Symbol(testExtendsImplicitDefault, Decl(narrowingByTypeofInSwitch.ts, 118, 1)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 120, 36)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 120, 36)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) case 'number': assertNumber(x); return; >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) case 'boolean': assertBoolean(x); return; >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) case 'function': assertAll(x); return; >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) case 'symbol': assertSymbol(x); return; >assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) } return assertAll(x); >assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 112, 53)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53)) } type L = (x: number) => string; ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 122, 10)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 130, 10)) type R = { x: string, y: number } ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 123, 10)) ->y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 123, 21)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 131, 10)) +>y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 131, 21)) function exhaustiveChecks(x: number | string | L | R): string { ->exhaustiveChecks : Symbol(exhaustiveChecks, Decl(narrowingByTypeofInSwitch.ts, 123, 33)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) +>exhaustiveChecks : Symbol(exhaustiveChecks, Decl(narrowingByTypeofInSwitch.ts, 131, 33)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) case 'number': return x.toString(2); >x.toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) >toString : Symbol(Number.toString, Decl(lib.d.ts, --, --)) case 'string': return x; ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) case 'function': return x(42); ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) case 'object': return x.x; ->x.x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 123, 10)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 125, 26)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 123, 10)) +>x.x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 131, 10)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 131, 10)) } } function exhaustiveChecksGenerics(x: T): string { ->exhaustiveChecksGenerics : Symbol(exhaustiveChecksGenerics, Decl(narrowingByTypeofInSwitch.ts, 132, 1)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 134, 34)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) ->T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 134, 34)) +>exhaustiveChecksGenerics : Symbol(exhaustiveChecksGenerics, Decl(narrowingByTypeofInSwitch.ts, 140, 1)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 142, 34)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) +>T : Symbol(T, Decl(narrowingByTypeofInSwitch.ts, 142, 34)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) case 'number': return x.toString(2); >x.toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --) ... and 2 more) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) >toString : Symbol(toString, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --) ... and 2 more) case 'string': return x; ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) case 'function': return (x as L)(42); // Can't narrow generic ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) case 'object': return (x as R).x; // Can't narrow generic ->(x as R).x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 123, 10)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 134, 69)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 123, 10)) +>(x as R).x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 131, 10)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 131, 10)) } } function multipleGeneric(xy: X | Y): [X, string] | [Y, number] { ->multipleGeneric : Symbol(multipleGeneric, Decl(narrowingByTypeofInSwitch.ts, 141, 1)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 143, 25)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 143, 37)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 143, 25)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 143, 37)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 143, 25)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 143, 37)) +>multipleGeneric : Symbol(multipleGeneric, Decl(narrowingByTypeofInSwitch.ts, 149, 1)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 25)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 37)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 25)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 37)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 25)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 37)) switch (typeof xy) { ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) case 'function': return [xy, xy(42)]; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) case 'object': return [xy, xy.y]; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) ->xy.y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 123, 21)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) ->y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 123, 21)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) +>xy.y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 131, 21)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) +>y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 131, 21)) default: return assertNever(xy); >assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 143, 51)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 51)) } } function multipleGenericFuse(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] { ->multipleGenericFuse : Symbol(multipleGenericFuse, Decl(narrowingByTypeofInSwitch.ts, 149, 1)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 29)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 50)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 73)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 29)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 50)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 29)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 50)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 151, 29)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 151, 50)) +>multipleGenericFuse : Symbol(multipleGenericFuse, Decl(narrowingByTypeofInSwitch.ts, 157, 1)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 29)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 50)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 29)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 50)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 29)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 50)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 29)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 50)) switch (typeof xy) { ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 73)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73)) case 'function': return [xy, 1]; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 73)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73)) case 'object': return [xy, 'two']; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 73)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73)) case 'number': return [xy] ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 151, 73)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73)) } } function multipleGenericExhaustive(xy: X | Y): [X, string] | [Y, number] { ->multipleGenericExhaustive : Symbol(multipleGenericExhaustive, Decl(narrowingByTypeofInSwitch.ts, 157, 1)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 35)) ->L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 120, 1)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 47)) ->R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 122, 31)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 35)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 47)) ->X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 159, 35)) ->Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 159, 47)) +>multipleGenericExhaustive : Symbol(multipleGenericExhaustive, Decl(narrowingByTypeofInSwitch.ts, 165, 1)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 167, 35)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 128, 1)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 167, 47)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 130, 31)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 167, 35)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 167, 47)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 167, 35)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 167, 47)) switch (typeof xy) { ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) case 'object': return [xy, xy.y]; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) ->xy.y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 123, 21)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) ->y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 123, 21)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) +>xy.y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 131, 21)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) +>y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 131, 21)) case 'function': return [xy, xy(42)]; ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) ->xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 61)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61)) } } function switchOrdering(x: string | number | boolean) { ->switchOrdering : Symbol(switchOrdering, Decl(narrowingByTypeofInSwitch.ts, 164, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>switchOrdering : Symbol(switchOrdering, Decl(narrowingByTypeofInSwitch.ts, 172, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) case 'string': return assertString(x); >assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) case 'number': return assertNumber(x); >assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) case 'boolean': return assertBoolean(x); >assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) case 'number': return assertNever(x); >assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 166, 24)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 174, 24)) } } function switchOrderingWithDefault(x: string | number | boolean) { ->switchOrderingWithDefault : Symbol(switchOrderingWithDefault, Decl(narrowingByTypeofInSwitch.ts, 173, 1)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>switchOrderingWithDefault : Symbol(switchOrderingWithDefault, Decl(narrowingByTypeofInSwitch.ts, 181, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) function local(y: string | number | boolean) { ->local : Symbol(local, Decl(narrowingByTypeofInSwitch.ts, 175, 66)) ->y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 176, 19)) +>local : Symbol(local, Decl(narrowingByTypeofInSwitch.ts, 183, 66)) +>y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 184, 19)) return x; ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) } switch (typeof x) { ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) case 'string': case 'number': default: return local(x) ->local : Symbol(local, Decl(narrowingByTypeofInSwitch.ts, 175, 66)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>local : Symbol(local, Decl(narrowingByTypeofInSwitch.ts, 183, 66)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) case 'string': return assertNever(x); >assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) case 'number': return assertNever(x); >assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) ->x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 175, 35)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35)) + } +} + +function fallThroughTest(x: string | number | boolean | object) { +>fallThroughTest : Symbol(fallThroughTest, Decl(narrowingByTypeofInSwitch.ts, 194, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + switch (typeof x) { +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + case 'number': + assertNumber(x) +>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + case 'string': + assertStringOrNumber(x) +>assertStringOrNumber : Symbol(assertStringOrNumber, Decl(narrowingByTypeofInSwitch.ts, 34, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + break; + default: + assertObject(x); +>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + case 'number': + case 'boolean': + assertBooleanOrObject(x); +>assertBooleanOrObject : Symbol(assertBooleanOrObject, Decl(narrowingByTypeofInSwitch.ts, 38, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 196, 25)) + + break; } } diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 785bdd23609d5..8672f4c9e7d09 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -73,6 +73,22 @@ function assertAll(x: Basic) { >x : Basic } +function assertStringOrNumber(x: string | number) { +>assertStringOrNumber : (x: string | number) => string | number +>x : string | number + + return x; +>x : string | number +} + +function assertBooleanOrObject(x: boolean | object) { +>assertBooleanOrObject : (x: boolean | object) => boolean | object +>x : boolean | object + + return x; +>x : boolean | object +} + type Basic = number | boolean | string | symbol | object | Function | undefined; >Basic : Basic >Function : Function @@ -693,3 +709,49 @@ function switchOrderingWithDefault(x: string | number | boolean) { } } +function fallThroughTest(x: string | number | boolean | object) { +>fallThroughTest : (x: string | number | boolean | object) => void +>x : string | number | boolean | object + + switch (typeof x) { +>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number | boolean | object + + case 'number': +>'number' : "number" + + assertNumber(x) +>assertNumber(x) : number +>assertNumber : (x: number) => number +>x : number + + case 'string': +>'string' : "string" + + assertStringOrNumber(x) +>assertStringOrNumber(x) : string | number +>assertStringOrNumber : (x: string | number) => string | number +>x : string | number + + break; + default: + assertObject(x); +>assertObject(x) : object +>assertObject : (x: object) => object +>x : object + + case 'number': +>'number' : "number" + + case 'boolean': +>'boolean' : "boolean" + + assertBooleanOrObject(x); +>assertBooleanOrObject(x) : boolean | object +>assertBooleanOrObject : (x: boolean | object) => boolean | object +>x : boolean | object + + break; + } +} + diff --git a/tests/cases/compiler/narrowingByTypeofInSwitch.ts b/tests/cases/compiler/narrowingByTypeofInSwitch.ts index aadd351b87e00..252c1d9445ac9 100644 --- a/tests/cases/compiler/narrowingByTypeofInSwitch.ts +++ b/tests/cases/compiler/narrowingByTypeofInSwitch.ts @@ -37,6 +37,14 @@ function assertAll(x: Basic) { return x; } +function assertStringOrNumber(x: string | number) { + return x; +} + +function assertBooleanOrObject(x: boolean | object) { + return x; +} + type Basic = number | boolean | string | symbol | object | Function | undefined; function testUnion(x: Basic) { @@ -188,3 +196,19 @@ function switchOrderingWithDefault(x: string | number | boolean) { case 'number': return assertNever(x); } } + +function fallThroughTest(x: string | number | boolean | object) { + switch (typeof x) { + case 'number': + assertNumber(x) + case 'string': + assertStringOrNumber(x) + break; + default: + assertObject(x); + case 'number': + case 'boolean': + assertBooleanOrObject(x); + break; + } +}