@@ -15317,6 +15317,32 @@ namespace ts {
15317
15317
return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
15318
15318
}
15319
15319
15320
+ function getImpliedTypeFromTypeofCase(type: Type, text: string) {
15321
+ switch (text) {
15322
+ case "function":
15323
+ return type.flags & TypeFlags.Any ? type : globalFunctionType;
15324
+ case "object":
15325
+ return type.flags & TypeFlags.Unknown ? getUnionType([nonPrimitiveType, nullType]) : type;
15326
+ default:
15327
+ return typeofTypesByName.get(text) || type;
15328
+ }
15329
+ }
15330
+
15331
+ function narrowTypeForTypeofSwitch(candidate: Type) {
15332
+ return (type: Type) => {
15333
+ if (isTypeSubtypeOf(candidate, type)) {
15334
+ return candidate;
15335
+ }
15336
+ if (type.flags & TypeFlags.Instantiable) {
15337
+ const constraint = getBaseConstraintOfType(type) || anyType;
15338
+ if (isTypeSubtypeOf(candidate, constraint)) {
15339
+ return getIntersectionType([type, candidate]);
15340
+ }
15341
+ }
15342
+ return type;
15343
+ };
15344
+ }
15345
+
15320
15346
function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
15321
15347
const switchWitnesses = getSwitchClauseTypeOfWitnesses(switchStatement);
15322
15348
if (!switchWitnesses.length) {
@@ -15334,7 +15360,7 @@ namespace ts {
15334
15360
// that we don't have to worry about undefined
15335
15361
// in the witness array.
15336
15362
const witnesses = <string[]>switchWitnesses.filter(witness => witness !== undefined);
15337
- // The adjust clause start and end after removing the `default` statement.
15363
+ // The adjusted clause start and end after removing the `default` statement.
15338
15364
const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
15339
15365
const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
15340
15366
clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
@@ -15344,6 +15370,9 @@ namespace ts {
15344
15370
clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
15345
15371
switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
15346
15372
}
15373
+ if (hasDefaultClause) {
15374
+ return filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts);
15375
+ }
15347
15376
/*
15348
15377
The implied type is the raw type suggested by a
15349
15378
value being caught in this clause.
@@ -15372,26 +15401,11 @@ namespace ts {
15372
15401
boolean. We know that number cannot be selected
15373
15402
because it is caught in the first clause.
15374
15403
*/
15375
- if (!(hasDefaultClause || (type.flags & TypeFlags.Union))) {
15376
- let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => typeofTypesByName.get(text) || neverType)), switchFacts);
15377
- if (impliedType.flags & TypeFlags.Union) {
15378
- impliedType = getAssignmentReducedType(impliedType as UnionType, getBaseConstraintOfType(type) || type);
15379
- }
15380
- if (!(impliedType.flags & TypeFlags.Never)) {
15381
- if (isTypeSubtypeOf(impliedType, type)) {
15382
- return impliedType;
15383
- }
15384
- if (type.flags & TypeFlags.Instantiable) {
15385
- const constraint = getBaseConstraintOfType(type) || anyType;
15386
- if (isTypeSubtypeOf(impliedType, constraint)) {
15387
- return getIntersectionType([type, impliedType]);
15388
- }
15389
- }
15390
- }
15404
+ let impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => getImpliedTypeFromTypeofCase(type, text))), switchFacts);
15405
+ if (impliedType.flags & TypeFlags.Union) {
15406
+ impliedType = getAssignmentReducedType(impliedType as UnionType, getBaseConstraintOrType(type));
15391
15407
}
15392
- return hasDefaultClause ?
15393
- filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts) :
15394
- getTypeWithFacts(type, switchFacts);
15408
+ return getTypeWithFacts(mapType(type, narrowTypeForTypeofSwitch(impliedType)), switchFacts);
15395
15409
}
15396
15410
15397
15411
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
0 commit comments