@@ -15441,6 +15441,32 @@ namespace ts {
15441
15441
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
15442
15442
}
15443
15443
15444
+ function getImpliedTypeFromTypeofCase(type: Type, text: string) {
15445
+ switch (text) {
15446
+ case "function":
15447
+ return type.flags & TypeFlags.Any ? type : globalFunctionType;
15448
+ case "object":
15449
+ return type.flags & TypeFlags.Unknown ? getUnionType([nonPrimitiveType, nullType]) : type;
15450
+ default:
15451
+ return typeofTypesByName.get(text) || type;
15452
+ }
15453
+ }
15454
+
15455
+ function narrowTypeForTypeofSwitch(candidate: Type) {
15456
+ return (type: Type) => {
15457
+ if (isTypeSubtypeOf(candidate, type)) {
15458
+ return candidate;
15459
+ }
15460
+ if (type.flags & TypeFlags.Instantiable) {
15461
+ const constraint = getBaseConstraintOfType(type) || anyType;
15462
+ if (isTypeSubtypeOf(candidate, constraint)) {
15463
+ return getIntersectionType([type, candidate]);
15464
+ }
15465
+ }
15466
+ return type;
15467
+ };
15468
+ }
15469
+
15444
15470
function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
15445
15471
const switchWitnesses = getSwitchClauseTypeOfWitnesses(switchStatement);
15446
15472
if (!switchWitnesses.length) {
@@ -15458,7 +15484,7 @@ namespace ts {
15458
15484
// that we don't have to worry about undefined
15459
15485
// in the witness array.
15460
15486
const witnesses = <string[]>switchWitnesses.filter(witness => witness !== undefined);
15461
- // The adjust clause start and end after removing the `default` statement.
15487
+ // The adjusted clause start and end after removing the `default` statement.
15462
15488
const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
15463
15489
const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
15464
15490
clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
@@ -15468,6 +15494,9 @@ namespace ts {
15468
15494
clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
15469
15495
switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
15470
15496
}
15497
+ if (hasDefaultClause) {
15498
+ return filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts);
15499
+ }
15471
15500
/*
15472
15501
The implied type is the raw type suggested by a
15473
15502
value being caught in this clause.
@@ -15496,26 +15525,11 @@ namespace ts {
15496
15525
boolean. We know that number cannot be selected
15497
15526
because it is caught in the first clause.
15498
15527
*/
15499
- if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) {
15500
- let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => typeofTypesByName.get(text) || neverType)), switchFacts);
15501
- if (impliedType.flags & TypeFlags.Union) {
15502
- impliedType = getAssignmentReducedType(impliedType as UnionType, getBaseConstraintOfType(type) || type);
15503
- }
15504
- if (!(impliedType.flags & TypeFlags.Never)) {
15505
- if (isTypeSubtypeOf(impliedType, type)) {
15506
- return impliedType;
15507
- }
15508
- if (type.flags & TypeFlags.Instantiable) {
15509
- const constraint = getBaseConstraintOfType(type) || anyType;
15510
- if (isTypeSubtypeOf(impliedType, constraint)) {
15511
- return getIntersectionType([type, impliedType]);
15512
- }
15513
- }
15514
- }
15528
+ let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => getImpliedTypeFromTypeofCase(type, text))), switchFacts);
15529
+ if (impliedType.flags & TypeFlags.Union) {
15530
+ impliedType = getAssignmentReducedType(impliedType as UnionType, getBaseConstraintOrType(type));
15515
15531
}
15516
- return hasDefaultClause ?
15517
- filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts) :
15518
- getTypeWithFacts(type, switchFacts);
15532
+ return getTypeWithFacts(mapType(type, narrowTypeForTypeofSwitch(impliedType)), switchFacts);
15519
15533
}
15520
15534
15521
15535
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
0 commit comments