@@ -12840,6 +12840,8 @@ namespace ts {
12840
12840
return links.switchTypes;
12841
12841
}
12842
12842
12843
+ // Get the types from all cases in a switch on `typeof`. An
12844
+ // `undefined` element denotes an explicit `default` clause.
12843
12845
function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] {
12844
12846
const witnesses: (string | undefined)[] = [];
12845
12847
for (const clause of switchStatement.caseBlock.clauses) {
@@ -13584,6 +13586,7 @@ namespace ts {
13584
13586
// that we don't have to worry about undefined
13585
13587
// in the witness array.
13586
13588
const witnesses = <string[]>switchWitnesses.filter(witness => witness !== undefined);
13589
+ // The adjust clause start and end after removing the `default` statement.
13587
13590
const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
13588
13591
const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
13589
13592
clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
@@ -13593,26 +13596,34 @@ namespace ts {
13593
13596
clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
13594
13597
switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
13595
13598
}
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
+ */
13616
13627
if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) {
13617
13628
let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => typeofTypesByName.get(text) || neverType)), switchFacts);
13618
13629
if (impliedType.flags & TypeFlags.Union) {
0 commit comments