mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #21957 from jack-williams/typeof-in-switch
Fix #2214. Support narrowing with typeof in switch condition.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user