@@ -19725,6 +19725,11 @@ namespace ts {
1972519725 return TypeFacts.All;
1972619726 }
1972719727
19728+ /**
19729+ * It might work differently from what you think.
19730+ * For example, fact1 is "it is number1", fact2 is "it is not number1". Now given a number and facts including both fact1 and fact2,
19731+ * if you get correct facts from the number, then all numbers meets the condition, for 1 meets facts1, and others meets fact2.
19732+ */
1972819733 function getTypeWithFacts(type: Type, include: TypeFacts) {
1972919734 return filterType(type, t => (getTypeFacts(t) & include) !== 0);
1973019735 }
@@ -20614,7 +20619,7 @@ namespace ts {
2061420619 if (isMatchingReference(reference, expr)) {
2061520620 type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
2061620621 }
20617- else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) {
20622+ else if (expr.kind === SyntaxKind.TypeOfExpression){// && isMatchingReference(reference, (expr as TypeOfExpression).expression)) {
2061820623 type = narrowBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
2061920624 }
2062020625 else {
@@ -20623,10 +20628,10 @@ namespace ts {
2062320628 type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd,
2062420629 t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never)));
2062520630 }
20626- else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) {
20627- type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd,
20628- t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (<StringLiteralType>t).value === "undefined"));
20629- }
20631+ // else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) {
20632+ // type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd,
20633+ // t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (<StringLiteralType>t).value === "undefined"));
20634+ // }
2063020635 }
2063120636 if (isMatchingReferenceDiscriminant(expr, type)) {
2063220637 type = narrowTypeByDiscriminant(type, expr as AccessExpression,
@@ -21150,9 +21155,10 @@ namespace ts {
2115021155
2115121156 const nonCallExpressionWithOutKeyword = expressionWithOutKeyword;
2115221157 // getTypeOfNode
21153- // check some condition, if not meet, it means we could not handle this confition.
21158+ // check some condition, if not meet, it means we could not handle this confition.
2115421159
2115521160 if ((nonCallExpressionWithOutKeyword.kind !== SyntaxKind.Identifier && !isAccessExpression(nonCallExpressionWithOutKeyword))) {// || (<AccessExpression>expressionWithOutKeyword).expression.kind === SyntaxKind.ThisKeyword) {
21161+ console.log("Error1\n");
2115621162 return undefined;
2115721163 }
2115821164 const depth = getTypeDepthIfMatch(nonCallExpressionWithOutKeyword, type);
@@ -21162,9 +21168,10 @@ namespace ts {
2116221168 const propertyPaths = getPropertyPathsOfAccessExpression(<AccessExpression>nonCallExpressionWithOutKeyword, depth);
2116321169 if (!propertyPaths) {
2116421170 // Not expected here should return. But for the situation not considered, I add this.
21171+ console.log("Error2\n");
2116521172 return undefined;
2116621173 }
21167- const propertyTypeArray = type.types.map(type => getPropertyTypeFromReferenceAccordingToPath(type, propertyPaths! , callExpressionFlag));
21174+ const propertyTypeArray = type.types.map(type => getPropertyTypeFromReferenceAccordingToPath(type, propertyPaths, callExpressionFlag));
2116821175 // if propertyTypeArray has unedfined value, it means sometype in the union type could not reach the path.
2116921176 // This should be an error which is not handled by this function, and we just not continue filter tyopes.
2117021177 if (propertyTypeArray.some(type => !type)) {
@@ -21193,47 +21200,37 @@ namespace ts {
2119321200 if (!isMatchingReference(reference, target)) {
2119421201 if (type.flags & TypeFlags.Union) {
2119521202 let propertyTypeArray: Type[] | undefined;
21196- let secondFilter = false;
21203+ let notNullOrUndefinedFilter = false; // the aim of this filter is type has 'undefined',filter it out from result.
2119721204 const isExpressionContainOptionalChain = isAccessExpressionContainOptionalChain(typeOfExpr.expression);
2119821205 // ~undefined means other values except undefiend. boolean, bigint....
21199- if (assumeTrue && literal.text !== "undefined") {
21206+ if ((assumeTrue && literal.text !== "undefined") || (!assumeTrue && literal.text === "undefined")) {
21207+ // !== undefined
2120021208 // === ~undefined
2120121209 // use full expression to narrow
21202- propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression, false);
21203- secondFilter = true; // the aim of this filter is type has 'undefined',filter it out from result.
21210+ propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression,/* optionalChainSlice */ false);
21211+ notNullOrUndefinedFilter = true;
2120421212 }
2120521213 else {
21206- // !== ~undefined, === undefined, !==undefined
21214+ // !== ~undefined, === undefined
2120721215 // use non-OptionalChain part to narrow
21208- propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression, true);
21209- if (!assumeTrue && literal.text === "undefined") {
21210- // !==undefined
21211- secondFilter = true;
21212- }
21216+ propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression,/* optionalChainSlice */ true);
2121321217 if (isExpressionContainOptionalChain) {
21214- facts = TypeFacts.All;
21218+ facts = TypeFacts.None; // The aim is no filter.
2121521219 }
2121621220 }
2121721221 if (!propertyTypeArray) {
2121821222 return type;
2121921223 }
2122021224 const tmp2 = propertyTypeArray.map(propertyType => {
21221- const filteredType = getTypeWithFacts(propertyType, facts);
21222- const filteredType2 = getTypeWithFacts(propertyType, TypeFacts.NEUndefined);
21223- const filteredType3 = getTypeWithFacts(propertyType, TypeFacts.NENull);
21224- if (secondFilter) {
21225- if ((filteredType.flags & TypeFlags.Never) || (filteredType2.flags & TypeFlags.Never) || (filteredType3.flags & TypeFlags.Never)) {
21226- return false;
21227- }
21228- else {
21229- return true;
21230- }
21225+ const propertyTypeFacts = getTypeFacts(propertyType);
21226+ if (notNullOrUndefinedFilter) {
21227+ facts |= TypeFacts.NEUndefined | TypeFacts.NENull;
2123121228 }
21232- if (filteredType.flags & TypeFlags.Never ) {
21233- return false ;
21229+ if ((propertyTypeFacts & facts) === facts ) {
21230+ return true ;
2123421231 }
2123521232 else {
21236- return true ;
21233+ return false ;
2123721234 }
2123821235 });
2123921236 const result = (<UnionType>type).types.filter((_t, index) => {
@@ -21397,55 +21394,53 @@ namespace ts {
2139721394 */
2139821395 const tmpExpression = (<TypeOfExpression>switchStatement.expression).expression;
2139921396 const impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => getImpliedTypeFromTypeofGuard(type, text) || type)), switchFacts);
21400- if (isMatchingReference(reference, tmpExpression)){
21397+ if (isMatchingReference(reference, tmpExpression)) {
2140121398 if (hasDefaultClause) {
2140221399 return filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts);
2140321400 }
2140421401 return getTypeWithFacts(mapType(type, narrowUnionMemberByTypeof(impliedType)), switchFacts);
2140521402 }
2140621403 let propertyTypeArray: Type[] | undefined;
21407- let secondFilter = false;
21404+ let notNullOrUndefinedFilter = false;
2140821405 const isExpressionContainOptionalChain = isAccessExpressionContainOptionalChain(tmpExpression);
2140921406 let facts = switchFacts;
21407+
2141021408 // ~undefined means other values except undefiend. boolean, bigint....
21411- if (switchFacts & TypeFacts.NEUndefined ) {
21412- // === ~undefined
21409+ if (facts & 0b111111 && !(facts & TypeFacts.EQUndefined) ) {
21410+ // === ~undefined and not === undefiend
2141321411 // use full expression to narrow
21414- propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, tmpExpression, false);
21415- secondFilter = true; // the aim of this filter is type has 'undefined',filter it out from result.
21412+ propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, tmpExpression, /* optionalChainSlice */ false);
21413+ notNullOrUndefinedFilter = true;
2141621414 }
2141721415 else {
2141821416 // !== ~undefined, === undefined, !==undefined
2141921417 // use non-OptionalChain part to narrow
21420- propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, tmpExpression, true);
21418+ propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, tmpExpression, /* optionalChainSlice */ true);
21419+ if (facts & TypeFacts.NEUndefined) {
21420+ // !== undefined
21421+ notNullOrUndefinedFilter = true;
21422+ }
2142121423 if (isExpressionContainOptionalChain) {
21422- facts = TypeFacts.All;
21424+ facts = TypeFacts.All; // The aim is no filter.
2142321425 }
2142421426 }
2142521427 if (!propertyTypeArray) {
21426- return type;
21428+ return type; // return type;
2142721429 }
2142821430 const tmp2 = propertyTypeArray.map(propertyType => {
21429- let filteredType;
21430- if (hasDefaultClause) {
21431- filteredType = filterType(propertyType, t => (getTypeFacts(t) & switchFacts) === switchFacts);
21432- } else {
21433- filteredType = getTypeWithFacts(mapType(propertyType, narrowUnionMemberByTypeof(impliedType)), facts);
21431+ const propertyTypeFacts = getTypeFacts(propertyType);
21432+ let secondFacts: TypeFacts;
21433+ if (notNullOrUndefinedFilter) {
21434+ secondFacts = TypeFacts.NEUndefinedOrNull;
2143421435 }
21435- const filteredType2 = getTypeWithFacts(propertyType, TypeFacts.NEUndefined);
21436- if (secondFilter) {
21437- if ((filteredType.flags & TypeFlags.Never) || (filteredType2.flags & TypeFlags.Never)) {
21438- return false;
21439- }
21440- else {
21441- return true;
21442- }
21436+ else {
21437+ secondFacts = TypeFacts.None; // The aim is no filter.
2144321438 }
21444- if (filteredType.flags & TypeFlags.Never ) {
21445- return false ;
21439+ if ((propertyTypeFacts & facts) && (propertyTypeFacts & secondFacts) === secondFacts ) {
21440+ return true ;
2144621441 }
2144721442 else {
21448- return true ;
21443+ return false ;
2144921444 }
2145021445 });
2145121446 const result = (<UnionType>type).types.filter((_t, index) => {
@@ -29675,12 +29670,12 @@ namespace ts {
2967529670 }
2967629671 // If a type has been cached for the node, return it.
2967729672 // Note: this is not only cache, without this, some test case would always runs, such as binaryArithmeticControlFlowGraphNotTooLarge.
29678- // if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
29679- // const cachedType = flowTypeCache[getNodeId(node)];
29680- // if (cachedType) {
29681- // return cachedType;
29682- // }
29683- // }
29673+ if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
29674+ const cachedType = flowTypeCache[getNodeId(node)];
29675+ if (cachedType) {
29676+ return cachedType;
29677+ }
29678+ }
2968429679 const startInvocationCount = flowInvocationCount;
2968529680 const type = checkExpression(node);
2968629681 // If control flow analysis was required to determine the type, it is worth caching.
0 commit comments