@@ -591,6 +591,8 @@ import {
591
591
isLiteralExpressionOfObject,
592
592
isLiteralImportTypeNode,
593
593
isLiteralTypeNode,
594
+ isLogicalOrCoalescingBinaryExpression,
595
+ isLogicalOrCoalescingBinaryOperator,
594
596
isMetaProperty,
595
597
isMethodDeclaration,
596
598
isMethodSignature,
@@ -35561,13 +35563,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
35561
35563
setLeftType(state, leftType);
35562
35564
setLastResult(state, /*type*/ undefined);
35563
35565
const operator = operatorToken.kind;
35564
- if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
35565
- if (operator === SyntaxKind.AmpersandAmpersandToken) {
35566
- let parent = node.parent;
35567
- while (parent.kind === SyntaxKind.ParenthesizedExpression
35568
- || isBinaryExpression(parent) && (parent.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || parent.operatorToken.kind === SyntaxKind.BarBarToken)) {
35569
- parent = parent.parent;
35570
- }
35566
+ if (isLogicalOrCoalescingBinaryOperator(operator)) {
35567
+ let parent = node.parent;
35568
+ while (parent.kind === SyntaxKind.ParenthesizedExpression || isLogicalOrCoalescingBinaryExpression(parent)) {
35569
+ parent = parent.parent;
35570
+ }
35571
+ if (operator === SyntaxKind.AmpersandAmpersandToken || isIfStatement(parent)) {
35571
35572
checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined);
35572
35573
}
35573
35574
checkTruthinessOfType(leftType, node.left);
@@ -35656,7 +35657,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
35656
35657
return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword);
35657
35658
}
35658
35659
let leftType: Type;
35659
- if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken ) {
35660
+ if (isLogicalOrCoalescingBinaryOperator( operator) ) {
35660
35661
leftType = checkTruthinessExpression(left, checkMode);
35661
35662
}
35662
35663
else {
@@ -39921,19 +39922,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39921
39922
39922
39923
function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) {
39923
39924
if (!strictNullChecks) return;
39925
+ bothHelper(condExpr, body);
39926
+
39927
+ function bothHelper(condExpr: Expression, body: Expression | Statement | undefined) {
39928
+ condExpr = skipParentheses(condExpr);
39924
39929
39925
- helper(condExpr, body);
39926
- while (isBinaryExpression(condExpr) && condExpr.operatorToken.kind === SyntaxKind.BarBarToken) {
39927
- condExpr = condExpr.left;
39928
39930
helper(condExpr, body);
39931
+
39932
+ while (isBinaryExpression(condExpr) && (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.QuestionQuestionToken)) {
39933
+ condExpr = skipParentheses(condExpr.left);
39934
+ helper(condExpr, body);
39935
+ }
39929
39936
}
39930
39937
39931
39938
function helper(condExpr: Expression, body: Expression | Statement | undefined) {
39932
- const location = isBinaryExpression(condExpr) &&
39933
- (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)
39934
- ? condExpr.right
39935
- : condExpr;
39936
- if (isModuleExportsAccessExpression(location)) return;
39939
+ const location = isLogicalOrCoalescingBinaryExpression(condExpr) ? skipParentheses(condExpr.right) : condExpr;
39940
+ if (isModuleExportsAccessExpression(location)) {
39941
+ return;
39942
+ }
39943
+ if (isLogicalOrCoalescingBinaryExpression(location)) {
39944
+ bothHelper(location, body);
39945
+ return;
39946
+ }
39937
39947
const type = location === condExpr ? condType : checkTruthinessExpression(location);
39938
39948
const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression);
39939
39949
if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return;
@@ -39951,7 +39961,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39951
39961
39952
39962
const testedNode = isIdentifier(location) ? location
39953
39963
: isPropertyAccessExpression(location) ? location.name
39954
- : isBinaryExpression(location) && isIdentifier(location.right) ? location.right
39955
39964
: undefined;
39956
39965
const testedSymbol = testedNode && getSymbolAtLocation(testedNode);
39957
39966
if (!testedSymbol && !isPromise) {
0 commit comments