@@ -15441,6 +15441,32 @@ namespace ts {
1544115441 return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]);
1544215442 }
1544315443
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+
1544415470 function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
1544515471 const switchWitnesses = getSwitchClauseTypeOfWitnesses(switchStatement);
1544615472 if (!switchWitnesses.length) {
@@ -15458,7 +15484,7 @@ namespace ts {
1545815484 // that we don't have to worry about undefined
1545915485 // in the witness array.
1546015486 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.
1546215488 const fixedClauseStart = defaultCaseLocation < clauseStart ? clauseStart - 1 : clauseStart;
1546315489 const fixedClauseEnd = defaultCaseLocation < clauseEnd ? clauseEnd - 1 : clauseEnd;
1546415490 clauseWitnesses = witnesses.slice(fixedClauseStart, fixedClauseEnd);
@@ -15468,6 +15494,9 @@ namespace ts {
1546815494 clauseWitnesses = <string[]>switchWitnesses.slice(clauseStart, clauseEnd);
1546915495 switchFacts = getFactsFromTypeofSwitch(clauseStart, clauseEnd, <string[]>switchWitnesses, hasDefaultClause);
1547015496 }
15497+ if (hasDefaultClause) {
15498+ return filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts);
15499+ }
1547115500 /*
1547215501 The implied type is the raw type suggested by a
1547315502 value being caught in this clause.
@@ -15496,26 +15525,11 @@ namespace ts {
1549615525 boolean. We know that number cannot be selected
1549715526 because it is caught in the first clause.
1549815527 */
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));
1551515531 }
15516- return hasDefaultClause ?
15517- filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts) :
15518- getTypeWithFacts(type, switchFacts);
15532+ return getTypeWithFacts(mapType(type, narrowTypeForTypeofSwitch(impliedType)), switchFacts);
1551915533 }
1552015534
1552115535 function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
0 commit comments