@@ -18124,6 +18124,16 @@ namespace ts {
18124
18124
return false;
18125
18125
}
18126
18126
18127
+ function optionalChainContainsReference(source: Node, target: Node) {
18128
+ while (isOptionalChain(source)) {
18129
+ source = source.expression;
18130
+ if (isMatchingReference(source, target)) {
18131
+ return true;
18132
+ }
18133
+ }
18134
+ return false;
18135
+ }
18136
+
18127
18137
// Return true if target is a property access xxx.yyy, source is a property access xxx.zzz, the declared
18128
18138
// type of xxx is a union type, and yyy is a property that is possibly a discriminant. We consider a property
18129
18139
// a possible discriminant if its type differs in the constituents of containing union type, and if every
@@ -19350,6 +19360,14 @@ namespace ts {
19350
19360
if (isMatchingReference(reference, right)) {
19351
19361
return narrowTypeByEquality(type, operator, left, assumeTrue);
19352
19362
}
19363
+ if (assumeTrue && (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) {
19364
+ if (optionalChainContainsReference(left, reference)) {
19365
+ type = narrowTypeByOptionalChainContainment(type, operator, right);
19366
+ }
19367
+ else if (optionalChainContainsReference(right, reference)) {
19368
+ type = narrowTypeByOptionalChainContainment(type, operator, left);
19369
+ }
19370
+ }
19353
19371
if (isMatchingReferenceDiscriminant(left, declaredType)) {
19354
19372
return narrowTypeByDiscriminant(type, <AccessExpression>left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
19355
19373
}
@@ -19374,6 +19392,16 @@ namespace ts {
19374
19392
return type;
19375
19393
}
19376
19394
19395
+ function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression): Type {
19396
+ // We are in the true branch of obj?.foo === value or obj?.foo !== value. We remove undefined and null from
19397
+ // the type of obj if (a) the operator is === and the type of value doesn't include undefined or (b) the
19398
+ // operator is !== and the type of value is undefined.
19399
+ const valueType = getTypeOfExpression(value);
19400
+ return operator === SyntaxKind.EqualsEqualsEqualsToken && !(getTypeFacts(valueType) & TypeFacts.EQUndefined) ||
19401
+ operator === SyntaxKind.ExclamationEqualsEqualsToken && valueType.flags & TypeFlags.Undefined ?
19402
+ getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type;
19403
+ }
19404
+
19377
19405
function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type {
19378
19406
if (type.flags & TypeFlags.Any) {
19379
19407
return type;
0 commit comments