Merge pull request #21957 from jack-williams/typeof-in-switch

Fix #2214. Support narrowing with typeof in switch condition.
This commit is contained in:
Ryan Cavanaugh
2018-09-06 10:46:13 -07:00
committed by GitHub
6 changed files with 2136 additions and 0 deletions
+2
View File
@@ -735,6 +735,8 @@ namespace ts {
return isNarrowingBinaryExpression(<BinaryExpression>expr);
case SyntaxKind.PrefixUnaryExpression:
return (<PrefixUnaryExpression>expr).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((<PrefixUnaryExpression>expr).operand);
case SyntaxKind.TypeOfExpression:
return isNarrowingExpression((<TypeOfExpression>expr).expression);
}
return false;
}
+149
View File
@@ -14282,6 +14282,23 @@ namespace ts {
return links.switchTypes;
}
// Get the types from all cases in a switch on `typeof`. An
// `undefined` element denotes an explicit `default` clause.
function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] {
const witnesses: (string | undefined)[] = [];
for (const clause of switchStatement.caseBlock.clauses) {
if (clause.kind === SyntaxKind.CaseClause) {
if (clause.expression.kind === SyntaxKind.StringLiteral) {
witnesses.push((clause.expression as StringLiteral).text);
continue;
}
return emptyArray;
}
witnesses.push(/*explicitDefaultStatement*/ undefined);
}
return witnesses;
}
function eachTypeContainedIn(source: Type, types: Type[]) {
return source.flags & TypeFlags.Union ? !forEach((<UnionType>source).types, t => !contains(types, t)) : contains(types, source);
}
@@ -14704,6 +14721,9 @@ namespace ts {
expr as PropertyAccessExpression | ElementAccessExpression,
t => narrowTypeBySwitchOnDiscriminant(t, flow.switchStatement, flow.clauseStart, flow.clauseEnd));
}
else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) {
type = narrowBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
}
return createFlowType(type, isIncomplete(flowType));
}
@@ -15019,6 +15039,83 @@ namespace ts {
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
}
function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
const switchWitnesses = getSwitchClauseTypeOfWitnesses(switchStatement);
if (!switchWitnesses.length) {
return type;
}
// Equal start and end denotes implicit fallthrough; undefined marks explicit default clause
const defaultCaseLocation = findIndex(switchWitnesses, elem => elem === undefined);
const hasDefaultClause = clauseStart === clauseEnd || (defaultCaseLocation >= clauseStart && defaultCaseLocation < clauseEnd);
let clauseWitnesses: string[];
let switchFacts: TypeFacts;
if (defaultCaseLocation > -1) {
// We no longer need the undefined denoting an
// explicit default case. Remove the undefined and
// fix-up clauseStart and clauseEnd. This means
// that we don't have to worry about undefined
// in the witness array.
const witnesses = <string[]>switchWitnesses.filter(witness => witness !== undefined);
// The adjust clause start and end after removing the `default` statement.
const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
switchFacts = getFactsFromTypeofSwitch(fixedClauseStart, fixedClauseEnd, witnesses, hasDefaultClause);
}
else {
clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
}
/*
The implied type is the raw type suggested by a
value being caught in this clause.
When the clause contains a default case we ignore
the implied type and try to narrow using any facts
we can learn: see `switchFacts`.
Example:
switch (typeof x) {
case 'number':
case 'string': break;
default: break;
case 'number':
case 'boolean': break
}
In the first clause (case `number` and `string`) the
implied type is number | string.
In the default clause we de not compute an implied type.
In the third clause (case `number` and `boolean`)
the naive implied type is number | boolean, however
we use the type facts to narrow the implied type to
boolean. We know that number cannot be selected
because it is caught in the first clause.
*/
if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) {
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);
}
if (!(impliedType.flags & TypeFlags.Never)) {
if (isTypeSubtypeOf(impliedType, type)) {
return impliedType;
}
if (type.flags & TypeFlags.Instantiable) {
const constraint = getBaseConstraintOfType(type) || anyType;
if (isTypeSubtypeOf(impliedType, constraint)) {
return getIntersectionType([type, impliedType]);
}
}
}
}
return hasDefaultClause ?
filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts) :
getTypeWithFacts(type, switchFacts);
}
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
const left = getReferenceCandidate(expr.left);
if (!isMatchingReference(reference, left)) {
@@ -20572,10 +20669,62 @@ namespace ts {
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
/**
* Collect the TypeFacts learned from a typeof switch with
* total clauses `witnesses`, and the active clause ranging
* from `start` to `end`. Parameter `hasDefault` denotes
* whether the active clause contains a default clause.
*/
function getFactsFromTypeofSwitch(start: number, end: number, witnesses: string[], hasDefault: boolean): TypeFacts {
let facts: TypeFacts = TypeFacts.None;
// When in the default we only collect inequality facts
// because default is 'in theory' a set of infinite
// equalities.
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;
}
// 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);
}
// Add inequalities for types before the active clause unconditionally.
for (let i = 0; i < start; i++) {
facts |= typeofNEFacts.get(witnesses[i]) || TypeFacts.TypeofNEHostObject;
}
}
// When in an active clause without default the set of
// equalities is finite.
else {
// Add equalities for all types in the active clause.
for (let i = start; i < end; i++) {
facts |= typeofEQFacts.get(witnesses[i]) || 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);
}
}
return facts;
}
function isExhaustiveSwitchStatement(node: SwitchStatement): boolean {
if (!node.possiblyExhaustive) {
return false;
}
if (node.expression.kind === SyntaxKind.TypeOfExpression) {
const operandType = getTypeOfExpression((node.expression as TypeOfExpression).expression);
// This cast is safe because the switch is possibly exhaustive and does not contain a default case, so there can be no undefined.
const witnesses = <string[]>getSwitchClauseTypeOfWitnesses(node);
// notEqualFacts states that the type of the switched value is not equal to every type in the switch.
const notEqualFacts = getFactsFromTypeofSwitch(0, 0, witnesses, /*hasDefault*/ true);
const type = getBaseConstraintOfType(operandType) || operandType;
return !!(filterType(type, t => (getTypeFacts(t) & notEqualFacts) === notEqualFacts).flags & TypeFlags.Never);
}
const type = getTypeOfExpression(node.expression);
if (!isLiteralType(type)) {
return false;
@@ -0,0 +1,472 @@
//// [narrowingByTypeofInSwitch.ts]
function assertNever(x: never) {
return x;
}
function assertNumber(x: number) {
return x;
}
function assertBoolean(x: boolean) {
return x;
}
function assertString(x: string) {
return x;
}
function assertSymbol(x: symbol) {
return x;
}
function assertFunction(x: Function) {
return x;
}
function assertObject(x: object) {
return x;
}
function assertUndefined(x: undefined) {
return x;
}
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) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertObject(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertNever(x);
}
function testExtendsUnion<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertAll(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertAll(x);
}
function testAny(x: any) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertObject(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertAll(x); // is any
}
function a1(x: string | object | undefined) {
return x;
}
function testUnionExplicitDefault(x: Basic) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
default: a1(x); return;
}
}
function testUnionImplicitDefault(x: Basic) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
}
return a1(x);
}
function testExtendsExplicitDefault<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
default: assertAll(x); return;
}
}
function testExtendsImplicitDefault<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
}
return assertAll(x);
}
type L = (x: number) => string;
type R = { x: string, y: number }
function exhaustiveChecks(x: number | string | L | R): string {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return x(42);
case 'object': return x.x;
}
}
function exhaustiveChecksGenerics<T extends L | R | number | string>(x: T): string {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return (x as L)(42); // Can't narrow generic
case 'object': return (x as R).x; // Can't narrow generic
}
}
function multipleGeneric<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
switch (typeof xy) {
case 'function': return [xy, xy(42)];
case 'object': return [xy, xy.y];
default: return assertNever(xy);
}
}
function multipleGenericFuse<X extends L | number, Y extends R | number>(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] {
switch (typeof xy) {
case 'function': return [xy, 1];
case 'object': return [xy, 'two'];
case 'number': return [xy]
}
}
function multipleGenericExhaustive<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
switch (typeof xy) {
case 'object': return [xy, xy.y];
case 'function': return [xy, xy(42)];
}
}
function switchOrdering(x: string | number | boolean) {
switch (typeof x) {
case 'string': return assertString(x);
case 'number': return assertNumber(x);
case 'boolean': return assertBoolean(x);
case 'number': return assertNever(x);
}
}
function switchOrderingWithDefault(x: string | number | boolean) {
function local(y: string | number | boolean) {
return x;
}
switch (typeof x) {
case 'string':
case 'number':
default: return local(x)
case 'string': return assertNever(x);
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]
function assertNever(x) {
return x;
}
function assertNumber(x) {
return x;
}
function assertBoolean(x) {
return x;
}
function assertString(x) {
return x;
}
function assertSymbol(x) {
return x;
}
function assertFunction(x) {
return x;
}
function assertObject(x) {
return x;
}
function assertUndefined(x) {
return x;
}
function assertAll(x) {
return x;
}
function assertStringOrNumber(x) {
return x;
}
function assertBooleanOrObject(x) {
return x;
}
function testUnion(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertFunction(x);
return;
case 'symbol':
assertSymbol(x);
return;
case 'object':
assertObject(x);
return;
case 'string':
assertString(x);
return;
case 'undefined':
assertUndefined(x);
return;
}
assertNever(x);
}
function testExtendsUnion(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertAll(x);
return;
case 'symbol':
assertSymbol(x);
return;
case 'object':
assertAll(x);
return;
case 'string':
assertString(x);
return;
case 'undefined':
assertUndefined(x);
return;
}
assertAll(x);
}
function testAny(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertFunction(x);
return;
case 'symbol':
assertSymbol(x);
return;
case 'object':
assertObject(x);
return;
case 'string':
assertString(x);
return;
case 'undefined':
assertUndefined(x);
return;
}
assertAll(x); // is any
}
function a1(x) {
return x;
}
function testUnionExplicitDefault(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertFunction(x);
return;
case 'symbol':
assertSymbol(x);
return;
default:
a1(x);
return;
}
}
function testUnionImplicitDefault(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertFunction(x);
return;
case 'symbol':
assertSymbol(x);
return;
}
return a1(x);
}
function testExtendsExplicitDefault(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertAll(x);
return;
case 'symbol':
assertSymbol(x);
return;
default:
assertAll(x);
return;
}
}
function testExtendsImplicitDefault(x) {
switch (typeof x) {
case 'number':
assertNumber(x);
return;
case 'boolean':
assertBoolean(x);
return;
case 'function':
assertAll(x);
return;
case 'symbol':
assertSymbol(x);
return;
}
return assertAll(x);
}
function exhaustiveChecks(x) {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return x(42);
case 'object': return x.x;
}
}
function exhaustiveChecksGenerics(x) {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return x(42); // Can't narrow generic
case 'object': return x.x; // Can't narrow generic
}
}
function multipleGeneric(xy) {
switch (typeof xy) {
case 'function': return [xy, xy(42)];
case 'object': return [xy, xy.y];
default: return assertNever(xy);
}
}
function multipleGenericFuse(xy) {
switch (typeof xy) {
case 'function': return [xy, 1];
case 'object': return [xy, 'two'];
case 'number': return [xy];
}
}
function multipleGenericExhaustive(xy) {
switch (typeof xy) {
case 'object': return [xy, xy.y];
case 'function': return [xy, xy(42)];
}
}
function switchOrdering(x) {
switch (typeof x) {
case 'string': return assertString(x);
case 'number': return assertNumber(x);
case 'boolean': return assertBoolean(x);
case 'number': return assertNever(x);
}
}
function switchOrderingWithDefault(x) {
function local(y) {
return x;
}
switch (typeof x) {
case 'string':
case 'number':
default: return local(x);
case 'string': return assertNever(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;
}
}
@@ -0,0 +1,591 @@
=== tests/cases/compiler/narrowingByTypeofInSwitch.ts ===
function assertNever(x: never) {
>assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 0, 21))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 0, 21))
}
function assertNumber(x: number) {
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 4, 22))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 4, 22))
}
function assertBoolean(x: boolean) {
>assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 8, 23))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 8, 23))
}
function assertString(x: string) {
>assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 12, 22))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 12, 22))
}
function assertSymbol(x: symbol) {
>assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 16, 22))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 16, 22))
}
function assertFunction(x: Function) {
>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 20, 24))
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 20, 24))
}
function assertObject(x: object) {
>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 24, 22))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 24, 22))
}
function assertUndefined(x: undefined) {
>assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 28, 25))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 28, 25))
}
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, 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, 42, 1))
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
function testUnion(x: Basic) {
>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, 46, 19))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 46, 19))
case 'function': assertFunction(x); return;
>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1))
>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, 46, 19))
case 'object': assertObject(x); return;
>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1))
>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, 46, 19))
case 'undefined': assertUndefined(x); return;
>assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19))
}
assertNever(x);
>assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 46, 19))
}
function testExtendsUnion<T extends Basic>(x: T) {
>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, 59, 43))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 59, 43))
case 'function': assertAll(x); return;
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>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, 59, 43))
case 'object': assertAll(x); return;
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>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, 59, 43))
case 'undefined': assertUndefined(x); return;
>assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43))
}
assertAll(x);
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 59, 43))
}
function testAny(x: any) {
>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, 72, 17))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 72, 17))
case 'function': assertFunction(x); return;
>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1))
>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, 72, 17))
case 'object': assertObject(x); return;
>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1))
>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, 72, 17))
case 'undefined': assertUndefined(x); return;
>assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 26, 1))
>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, 72, 17))
}
function a1(x: string | object | undefined) {
>a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 83, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 85, 12))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 85, 12))
}
function testUnionExplicitDefault(x: Basic) {
>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, 89, 34))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 89, 34))
case 'function': assertFunction(x); return;
>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1))
>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, 89, 34))
default: a1(x); return;
>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, 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, 99, 34))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 99, 34))
case 'function': assertFunction(x); return;
>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1))
>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, 99, 34))
}
return a1(x);
>a1 : Symbol(a1, Decl(narrowingByTypeofInSwitch.ts, 83, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 99, 34))
}
function testExtendsExplicitDefault<T extends Basic>(x: T) {
>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, 109, 53))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 109, 53))
case 'function': assertAll(x); return;
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>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, 109, 53))
default: assertAll(x); return;
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 109, 53))
}
}
function testExtendsImplicitDefault<T extends Basic>(x: T) {
>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, 120, 53))
case 'number': assertNumber(x); return;
>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1))
>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, 120, 53))
case 'function': assertAll(x); return;
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>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, 120, 53))
}
return assertAll(x);
>assertAll : Symbol(assertAll, Decl(narrowingByTypeofInSwitch.ts, 30, 1))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 120, 53))
}
type L = (x: number) => string;
>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, 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, 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, 133, 26))
case 'number': return x.toString(2);
>x.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
case 'string': return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26))
case 'function': return x(42);
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 133, 26))
case 'object': return x.x;
>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<T extends L | R | number | string>(x: T): string {
>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, 142, 69))
case 'number': return x.toString(2);
>x.toString : Symbol(toString, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 2 more)
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 142, 69))
>toString : Symbol(toString, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 2 more)
case 'string': return x;
>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, 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, 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<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
>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, 151, 51))
case 'function': return [xy, xy(42)];
>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, 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, 151, 51))
}
}
function multipleGenericFuse<X extends L | number, Y extends R | number>(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] {
>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, 159, 73))
case 'function': return [xy, 1];
>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73))
case 'object': return [xy, 'two'];
>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73))
case 'number': return [xy]
>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 159, 73))
}
}
function multipleGenericExhaustive<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
>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, 167, 61))
case 'object': return [xy, xy.y];
>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, 167, 61))
>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 167, 61))
}
}
function switchOrdering(x: string | number | boolean) {
>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, 174, 24))
case 'string': return assertString(x);
>assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1))
>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, 174, 24))
case 'boolean': return assertBoolean(x);
>assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1))
>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, 174, 24))
}
}
function switchOrderingWithDefault(x: string | number | boolean) {
>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, 183, 66))
>y : Symbol(y, Decl(narrowingByTypeofInSwitch.ts, 184, 19))
return x;
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35))
}
switch (typeof x) {
>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 183, 35))
case 'string':
case 'number':
default: return local(x)
>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, 183, 35))
case 'number': return assertNever(x);
>assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0))
>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;
}
}
@@ -0,0 +1,708 @@
=== tests/cases/compiler/narrowingByTypeofInSwitch.ts ===
function assertNever(x: never) {
>assertNever : (x: never) => never
>x : never
return x;
>x : never
}
function assertNumber(x: number) {
>assertNumber : (x: number) => number
>x : number
return x;
>x : number
}
function assertBoolean(x: boolean) {
>assertBoolean : (x: boolean) => boolean
>x : boolean
return x;
>x : boolean
}
function assertString(x: string) {
>assertString : (x: string) => string
>x : string
return x;
>x : string
}
function assertSymbol(x: symbol) {
>assertSymbol : (x: symbol) => symbol
>x : symbol
return x;
>x : symbol
}
function assertFunction(x: Function) {
>assertFunction : (x: Function) => Function
>x : Function
return x;
>x : Function
}
function assertObject(x: object) {
>assertObject : (x: object) => object
>x : object
return x;
>x : object
}
function assertUndefined(x: undefined) {
>assertUndefined : (x: undefined) => undefined
>x : undefined
return x;
>x : undefined
}
function assertAll(x: Basic) {
>assertAll : (x: Basic) => Basic
>x : Basic
return x;
>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 testUnion(x: Basic) {
>testUnion : (x: Basic) => void
>x : Basic
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : Basic
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : boolean
case 'function': assertFunction(x); return;
>'function' : "function"
>assertFunction(x) : Function
>assertFunction : (x: Function) => Function
>x : Function
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : symbol
case 'object': assertObject(x); return;
>'object' : "object"
>assertObject(x) : object
>assertObject : (x: object) => object
>x : object
case 'string': assertString(x); return;
>'string' : "string"
>assertString(x) : string
>assertString : (x: string) => string
>x : string
case 'undefined': assertUndefined(x); return;
>'undefined' : "undefined"
>assertUndefined(x) : undefined
>assertUndefined : (x: undefined) => undefined
>x : undefined
}
assertNever(x);
>assertNever(x) : never
>assertNever : (x: never) => never
>x : never
}
function testExtendsUnion<T extends Basic>(x: T) {
>testExtendsUnion : <T extends Basic>(x: T) => void
>x : T
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : T
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : T & number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : (T & false) | (T & true)
case 'function': assertAll(x); return;
>'function' : "function"
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : T & symbol
case 'object': assertAll(x); return;
>'object' : "object"
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
case 'string': assertString(x); return;
>'string' : "string"
>assertString(x) : string
>assertString : (x: string) => string
>x : T & string
case 'undefined': assertUndefined(x); return;
>'undefined' : "undefined"
>assertUndefined(x) : undefined
>assertUndefined : (x: undefined) => undefined
>x : T & undefined
}
assertAll(x);
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
}
function testAny(x: any) {
>testAny : (x: any) => void
>x : any
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : any
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : boolean
case 'function': assertFunction(x); return;
>'function' : "function"
>assertFunction(x) : Function
>assertFunction : (x: Function) => Function
>x : any
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : symbol
case 'object': assertObject(x); return;
>'object' : "object"
>assertObject(x) : object
>assertObject : (x: object) => object
>x : any
case 'string': assertString(x); return;
>'string' : "string"
>assertString(x) : string
>assertString : (x: string) => string
>x : string
case 'undefined': assertUndefined(x); return;
>'undefined' : "undefined"
>assertUndefined(x) : undefined
>assertUndefined : (x: undefined) => undefined
>x : undefined
}
assertAll(x); // is any
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : any
}
function a1(x: string | object | undefined) {
>a1 : (x: string | object | undefined) => string | object | undefined
>x : string | object | undefined
return x;
>x : string | object | undefined
}
function testUnionExplicitDefault(x: Basic) {
>testUnionExplicitDefault : (x: Basic) => void
>x : Basic
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : Basic
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : boolean
case 'function': assertFunction(x); return;
>'function' : "function"
>assertFunction(x) : Function
>assertFunction : (x: Function) => Function
>x : Function
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : symbol
default: a1(x); return;
>a1(x) : string | object | undefined
>a1 : (x: string | object | undefined) => string | object | undefined
>x : string | object | undefined
}
}
function testUnionImplicitDefault(x: Basic) {
>testUnionImplicitDefault : (x: Basic) => string | object | undefined
>x : Basic
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : Basic
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : boolean
case 'function': assertFunction(x); return;
>'function' : "function"
>assertFunction(x) : Function
>assertFunction : (x: Function) => Function
>x : Function
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : symbol
}
return a1(x);
>a1(x) : string | object | undefined
>a1 : (x: string | object | undefined) => string | object | undefined
>x : string | object | undefined
}
function testExtendsExplicitDefault<T extends Basic>(x: T) {
>testExtendsExplicitDefault : <T extends Basic>(x: T) => void
>x : T
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : T
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : T & number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : (T & false) | (T & true)
case 'function': assertAll(x); return;
>'function' : "function"
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : T & symbol
default: assertAll(x); return;
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
}
}
function testExtendsImplicitDefault<T extends Basic>(x: T) {
>testExtendsImplicitDefault : <T extends Basic>(x: T) => string | number | boolean | symbol | object | undefined
>x : T
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : T
case 'number': assertNumber(x); return;
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : T & number
case 'boolean': assertBoolean(x); return;
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : (T & false) | (T & true)
case 'function': assertAll(x); return;
>'function' : "function"
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
case 'symbol': assertSymbol(x); return;
>'symbol' : "symbol"
>assertSymbol(x) : symbol
>assertSymbol : (x: symbol) => symbol
>x : T & symbol
}
return assertAll(x);
>assertAll(x) : Basic
>assertAll : (x: Basic) => Basic
>x : T
}
type L = (x: number) => string;
>L : L
>x : number
type R = { x: string, y: number }
>R : R
>x : string
>y : number
function exhaustiveChecks(x: number | string | L | R): string {
>exhaustiveChecks : (x: string | number | R | L) => string
>x : string | number | R | L
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | number | R | L
case 'number': return x.toString(2);
>'number' : "number"
>x.toString(2) : string
>x.toString : (radix?: number | undefined) => string
>x : number
>toString : (radix?: number | undefined) => string
>2 : 2
case 'string': return x;
>'string' : "string"
>x : string
case 'function': return x(42);
>'function' : "function"
>x(42) : string
>x : L
>42 : 42
case 'object': return x.x;
>'object' : "object"
>x.x : string
>x : R
>x : string
}
}
function exhaustiveChecksGenerics<T extends L | R | number | string>(x: T): string {
>exhaustiveChecksGenerics : <T extends string | number | R | L>(x: T) => string
>x : T
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : T
case 'number': return x.toString(2);
>'number' : "number"
>x.toString(2) : string
>x.toString : ((radix?: number | undefined) => string) | ((() => string) & ((radix?: number | undefined) => string)) | ((() => string) & ((radix?: number | undefined) => string)) | ((() => string) & ((radix?: number | undefined) => string))
>x : T & number
>toString : ((radix?: number | undefined) => string) | ((() => string) & ((radix?: number | undefined) => string)) | ((() => string) & ((radix?: number | undefined) => string)) | ((() => string) & ((radix?: number | undefined) => string))
>2 : 2
case 'string': return x;
>'string' : "string"
>x : T & string
case 'function': return (x as L)(42); // Can't narrow generic
>'function' : "function"
>(x as L)(42) : string
>(x as L) : L
>x as L : L
>x : T
>42 : 42
case 'object': return (x as R).x; // Can't narrow generic
>'object' : "object"
>(x as R).x : string
>(x as R) : R
>x as R : R
>x : T
>x : string
}
}
function multipleGeneric<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
>multipleGeneric : <X extends L, Y extends R>(xy: X | Y) => [X, string] | [Y, number]
>xy : X | Y
switch (typeof xy) {
>typeof xy : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>xy : X | Y
case 'function': return [xy, xy(42)];
>'function' : "function"
>[xy, xy(42)] : [X, string]
>xy : X
>xy(42) : string
>xy : X
>42 : 42
case 'object': return [xy, xy.y];
>'object' : "object"
>[xy, xy.y] : [Y, number]
>xy : Y
>xy.y : number
>xy : Y
>y : number
default: return assertNever(xy);
>assertNever(xy) : never
>assertNever : (x: never) => never
>xy : never
}
}
function multipleGenericFuse<X extends L | number, Y extends R | number>(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] {
>multipleGenericFuse : <X extends number | L, Y extends number | R>(xy: X | Y) => [X, number] | [Y, string] | [X | Y]
>xy : X | Y
switch (typeof xy) {
>typeof xy : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>xy : X | Y
case 'function': return [xy, 1];
>'function' : "function"
>[xy, 1] : [X, number]
>xy : X
>1 : 1
case 'object': return [xy, 'two'];
>'object' : "object"
>[xy, 'two'] : [Y, string]
>xy : Y
>'two' : "two"
case 'number': return [xy]
>'number' : "number"
>[xy] : [X | Y]
>xy : X | Y
}
}
function multipleGenericExhaustive<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
>multipleGenericExhaustive : <X extends L, Y extends R>(xy: X | Y) => [X, string] | [Y, number]
>xy : X | Y
switch (typeof xy) {
>typeof xy : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>xy : X | Y
case 'object': return [xy, xy.y];
>'object' : "object"
>[xy, xy.y] : [Y, number]
>xy : Y
>xy.y : number
>xy : Y
>y : number
case 'function': return [xy, xy(42)];
>'function' : "function"
>[xy, xy(42)] : [X, string]
>xy : X
>xy(42) : string
>xy : X
>42 : 42
}
}
function switchOrdering(x: string | number | boolean) {
>switchOrdering : (x: string | number | boolean) => string | number | boolean
>x : string | number | boolean
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | number | boolean
case 'string': return assertString(x);
>'string' : "string"
>assertString(x) : string
>assertString : (x: string) => string
>x : string
case 'number': return assertNumber(x);
>'number' : "number"
>assertNumber(x) : number
>assertNumber : (x: number) => number
>x : number
case 'boolean': return assertBoolean(x);
>'boolean' : "boolean"
>assertBoolean(x) : boolean
>assertBoolean : (x: boolean) => boolean
>x : boolean
case 'number': return assertNever(x);
>'number' : "number"
>assertNever(x) : never
>assertNever : (x: never) => never
>x : never
}
}
function switchOrderingWithDefault(x: string | number | boolean) {
>switchOrderingWithDefault : (x: string | number | boolean) => string | number | boolean
>x : string | number | boolean
function local(y: string | number | boolean) {
>local : (y: string | number | boolean) => string | number | boolean
>y : string | number | boolean
return x;
>x : string | number | boolean
}
switch (typeof x) {
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
>x : string | number | boolean
case 'string':
>'string' : "string"
case 'number':
>'number' : "number"
default: return local(x)
>local(x) : string | number | boolean
>local : (y: string | number | boolean) => string | number | boolean
>x : string | number | boolean
case 'string': return assertNever(x);
>'string' : "string"
>assertNever(x) : never
>assertNever : (x: never) => never
>x : never
case 'number': return assertNever(x);
>'number' : "number"
>assertNever(x) : never
>assertNever : (x: never) => never
>x : never
}
}
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;
}
}
@@ -0,0 +1,214 @@
// @strictNullChecks: true
// @strictFunctionTypes: true
function assertNever(x: never) {
return x;
}
function assertNumber(x: number) {
return x;
}
function assertBoolean(x: boolean) {
return x;
}
function assertString(x: string) {
return x;
}
function assertSymbol(x: symbol) {
return x;
}
function assertFunction(x: Function) {
return x;
}
function assertObject(x: object) {
return x;
}
function assertUndefined(x: undefined) {
return x;
}
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) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertObject(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertNever(x);
}
function testExtendsUnion<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertAll(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertAll(x);
}
function testAny(x: any) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
case 'object': assertObject(x); return;
case 'string': assertString(x); return;
case 'undefined': assertUndefined(x); return;
}
assertAll(x); // is any
}
function a1(x: string | object | undefined) {
return x;
}
function testUnionExplicitDefault(x: Basic) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
default: a1(x); return;
}
}
function testUnionImplicitDefault(x: Basic) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertFunction(x); return;
case 'symbol': assertSymbol(x); return;
}
return a1(x);
}
function testExtendsExplicitDefault<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
default: assertAll(x); return;
}
}
function testExtendsImplicitDefault<T extends Basic>(x: T) {
switch (typeof x) {
case 'number': assertNumber(x); return;
case 'boolean': assertBoolean(x); return;
case 'function': assertAll(x); return;
case 'symbol': assertSymbol(x); return;
}
return assertAll(x);
}
type L = (x: number) => string;
type R = { x: string, y: number }
function exhaustiveChecks(x: number | string | L | R): string {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return x(42);
case 'object': return x.x;
}
}
function exhaustiveChecksGenerics<T extends L | R | number | string>(x: T): string {
switch (typeof x) {
case 'number': return x.toString(2);
case 'string': return x;
case 'function': return (x as L)(42); // Can't narrow generic
case 'object': return (x as R).x; // Can't narrow generic
}
}
function multipleGeneric<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
switch (typeof xy) {
case 'function': return [xy, xy(42)];
case 'object': return [xy, xy.y];
default: return assertNever(xy);
}
}
function multipleGenericFuse<X extends L | number, Y extends R | number>(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] {
switch (typeof xy) {
case 'function': return [xy, 1];
case 'object': return [xy, 'two'];
case 'number': return [xy]
}
}
function multipleGenericExhaustive<X extends L, Y extends R>(xy: X | Y): [X, string] | [Y, number] {
switch (typeof xy) {
case 'object': return [xy, xy.y];
case 'function': return [xy, xy(42)];
}
}
function switchOrdering(x: string | number | boolean) {
switch (typeof x) {
case 'string': return assertString(x);
case 'number': return assertNumber(x);
case 'boolean': return assertBoolean(x);
case 'number': return assertNever(x);
}
}
function switchOrderingWithDefault(x: string | number | boolean) {
function local(y: string | number | boolean) {
return x;
}
switch (typeof x) {
case 'string':
case 'number':
default: return local(x)
case 'string': return assertNever(x);
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;
}
}