Skip to content

Commit 4d8529c

Browse files
committed
Improve comments in narrowBySwitchOnTypeOf
1 parent 6391742 commit 4d8529c

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12840,6 +12840,8 @@ namespace ts {
1284012840
return links.switchTypes;
1284112841
}
1284212842

12843+
// Get the types from all cases in a switch on `typeof`. An
12844+
// `undefined` element denotes an explicit `default` clause.
1284312845
function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] {
1284412846
const witnesses: (string | undefined)[] = [];
1284512847
for (const clause of switchStatement.caseBlock.clauses) {
@@ -13584,6 +13586,7 @@ namespace ts {
1358413586
// that we don't have to worry about undefined
1358513587
// in the witness array.
1358613588
const witnesses = <string[]>switchWitnesses.filter(witness => witness !== undefined);
13589+
// The adjust clause start and end after removing the `default` statement.
1358713590
const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
1358813591
const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
1358913592
clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
@@ -13593,26 +13596,34 @@ namespace ts {
1359313596
clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
1359413597
switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
1359513598
}
13596-
// The implied type is the raw type suggested by a
13597-
// value being caught in this clause.
13598-
// - If there is a default the implied type is not used.
13599-
// - Otherwise, take the union of the types in the
13600-
// clause. We narrow the union using facts to remove
13601-
// types that appear multiple types and are
13602-
// unreachable.
13603-
// Example:
13604-
//
13605-
// switch (typeof x) {
13606-
// case 'number':
13607-
// case 'string': break;
13608-
// default: break;
13609-
// case 'number':
13610-
// case 'boolean': break
13611-
// }
13612-
//
13613-
// The implied type of the first clause number | string.
13614-
// The implied type of the second clause is never, but this does not get used because it includes a default case.
13615-
// The implied type of the third clause is boolean (number has already be caught).
13599+
/*
13600+
The implied type is the raw type suggested by a
13601+
value being caught in this clause.
13602+
13603+
When the clause contains a default case we ignore
13604+
the implied type and try to narrow using any facts
13605+
we can learn: see `switchFacts`.
13606+
13607+
Example:
13608+
switch (typeof x) {
13609+
case 'number':
13610+
case 'string': break;
13611+
default: break;
13612+
case 'number':
13613+
case 'boolean': break
13614+
}
13615+
13616+
In the first clause (case `number` and `string`) the
13617+
implied type is number | string.
13618+
13619+
In the default clause we de not compute an implied type.
13620+
13621+
In the third clause (case `number` and `boolean`)
13622+
the naive implied type is number | boolean, however
13623+
we use the type facts to narrow the implied type to
13624+
boolean. We know that number cannot be selected
13625+
because it is caught in the first clause.
13626+
*/
1361613627
if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) {
1361713628
let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => typeofTypesByName.get(text) || neverType)), switchFacts);
1361813629
if (impliedType.flags & TypeFlags.Union) {

0 commit comments

Comments
 (0)