@@ -19725,6 +19725,11 @@ namespace ts {
19725
19725
return TypeFacts.All;
19726
19726
}
19727
19727
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
+ */
19728
19733
function getTypeWithFacts(type: Type, include: TypeFacts) {
19729
19734
return filterType(type, t => (getTypeFacts(t) & include) !== 0);
19730
19735
}
@@ -20614,7 +20619,7 @@ namespace ts {
20614
20619
if (isMatchingReference(reference, expr)) {
20615
20620
type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
20616
20621
}
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)) {
20618
20623
type = narrowBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
20619
20624
}
20620
20625
else {
@@ -20623,10 +20628,10 @@ namespace ts {
20623
20628
type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd,
20624
20629
t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never)));
20625
20630
}
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
+ // }
20630
20635
}
20631
20636
if (isMatchingReferenceDiscriminant(expr, type)) {
20632
20637
type = narrowTypeByDiscriminant(type, expr as AccessExpression,
@@ -21150,9 +21155,10 @@ namespace ts {
21150
21155
21151
21156
const nonCallExpressionWithOutKeyword = expressionWithOutKeyword;
21152
21157
// 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.
21154
21159
21155
21160
if ((nonCallExpressionWithOutKeyword.kind !== SyntaxKind.Identifier && !isAccessExpression(nonCallExpressionWithOutKeyword))) {// || (<AccessExpression>expressionWithOutKeyword).expression.kind === SyntaxKind.ThisKeyword) {
21161
+ console.log("Error1\n");
21156
21162
return undefined;
21157
21163
}
21158
21164
const depth = getTypeDepthIfMatch(nonCallExpressionWithOutKeyword, type);
@@ -21162,9 +21168,10 @@ namespace ts {
21162
21168
const propertyPaths = getPropertyPathsOfAccessExpression(<AccessExpression>nonCallExpressionWithOutKeyword, depth);
21163
21169
if (!propertyPaths) {
21164
21170
// Not expected here should return. But for the situation not considered, I add this.
21171
+ console.log("Error2\n");
21165
21172
return undefined;
21166
21173
}
21167
- const propertyTypeArray = type.types.map(type => getPropertyTypeFromReferenceAccordingToPath(type, propertyPaths! , callExpressionFlag));
21174
+ const propertyTypeArray = type.types.map(type => getPropertyTypeFromReferenceAccordingToPath(type, propertyPaths, callExpressionFlag));
21168
21175
// if propertyTypeArray has unedfined value, it means sometype in the union type could not reach the path.
21169
21176
// This should be an error which is not handled by this function, and we just not continue filter tyopes.
21170
21177
if (propertyTypeArray.some(type => !type)) {
@@ -21193,47 +21200,37 @@ namespace ts {
21193
21200
if (!isMatchingReference(reference, target)) {
21194
21201
if (type.flags & TypeFlags.Union) {
21195
21202
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.
21197
21204
const isExpressionContainOptionalChain = isAccessExpressionContainOptionalChain(typeOfExpr.expression);
21198
21205
// ~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
21200
21208
// === ~undefined
21201
21209
// 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;
21204
21212
}
21205
21213
else {
21206
- // !== ~undefined, === undefined, !==undefined
21214
+ // !== ~undefined, === undefined
21207
21215
// 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);
21213
21217
if (isExpressionContainOptionalChain) {
21214
- facts = TypeFacts.All;
21218
+ facts = TypeFacts.None; // The aim is no filter.
21215
21219
}
21216
21220
}
21217
21221
if (!propertyTypeArray) {
21218
21222
return type;
21219
21223
}
21220
21224
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;
21231
21228
}
21232
- if (filteredType.flags & TypeFlags.Never ) {
21233
- return false ;
21229
+ if ((propertyTypeFacts & facts) === facts ) {
21230
+ return true ;
21234
21231
}
21235
21232
else {
21236
- return true ;
21233
+ return false ;
21237
21234
}
21238
21235
});
21239
21236
const result = (<UnionType>type).types.filter((_t, index) => {
@@ -21397,55 +21394,53 @@ namespace ts {
21397
21394
*/
21398
21395
const tmpExpression = (<TypeOfExpression>switchStatement.expression).expression;
21399
21396
const impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => getImpliedTypeFromTypeofGuard(type, text) || type)), switchFacts);
21400
- if (isMatchingReference(reference, tmpExpression)){
21397
+ if (isMatchingReference(reference, tmpExpression)) {
21401
21398
if (hasDefaultClause) {
21402
21399
return filterType(type, t => (getTypeFacts(t) & switchFacts) === switchFacts);
21403
21400
}
21404
21401
return getTypeWithFacts(mapType(type, narrowUnionMemberByTypeof(impliedType)), switchFacts);
21405
21402
}
21406
21403
let propertyTypeArray: Type[] | undefined;
21407
- let secondFilter = false;
21404
+ let notNullOrUndefinedFilter = false;
21408
21405
const isExpressionContainOptionalChain = isAccessExpressionContainOptionalChain(tmpExpression);
21409
21406
let facts = switchFacts;
21407
+
21410
21408
// ~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
21413
21411
// 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;
21416
21414
}
21417
21415
else {
21418
21416
// !== ~undefined, === undefined, !==undefined
21419
21417
// 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
+ }
21421
21423
if (isExpressionContainOptionalChain) {
21422
- facts = TypeFacts.All;
21424
+ facts = TypeFacts.All; // The aim is no filter.
21423
21425
}
21424
21426
}
21425
21427
if (!propertyTypeArray) {
21426
- return type;
21428
+ return type; // return type;
21427
21429
}
21428
21430
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;
21434
21435
}
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.
21443
21438
}
21444
- if (filteredType.flags & TypeFlags.Never ) {
21445
- return false ;
21439
+ if ((propertyTypeFacts & facts) && (propertyTypeFacts & secondFacts) === secondFacts ) {
21440
+ return true ;
21446
21441
}
21447
21442
else {
21448
- return true ;
21443
+ return false ;
21449
21444
}
21450
21445
});
21451
21446
const result = (<UnionType>type).types.filter((_t, index) => {
@@ -29675,12 +29670,12 @@ namespace ts {
29675
29670
}
29676
29671
// If a type has been cached for the node, return it.
29677
29672
// 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
+ }
29684
29679
const startInvocationCount = flowInvocationCount;
29685
29680
const type = checkExpression(node);
29686
29681
// If control flow analysis was required to determine the type, it is worth caching.
0 commit comments