diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6ece23f022a..c0939c63fd2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18790,6 +18790,22 @@ namespace ts { return !(flow.flags & FlowFlags.PreFinally && (flow).lock.locked) && isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false); } + function isFalseExpression(expr: Expression): boolean { + const node = skipParentheses(expr); + if (node.kind === SyntaxKind.FalseKeyword) { + return true; + } + if (node.kind === SyntaxKind.BinaryExpression) { + if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { + return isFalseExpression((node).left) || isFalseExpression((node).right); + } + if ((node).operatorToken.kind === SyntaxKind.BarBarToken) { + return isFalseExpression((node).left) && isFalseExpression((node).right); + } + } + return false; + } + function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean { while (true) { if (flow === lastFlowNode) { @@ -18809,8 +18825,17 @@ namespace ts { } else if (flags & FlowFlags.Call) { const signature = getEffectsSignature((flow).node); - if (signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { - return false; + if (signature) { + const predicate = getTypePredicateOfSignature(signature); + if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier) { + const predicateArgument = (flow).node.arguments[predicate.parameterIndex]; + if (predicateArgument && isFalseExpression(predicateArgument)) { + return false; + } + } + if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { + return false; + } } flow = (flow).antecedent; } @@ -19049,6 +19074,9 @@ namespace ts { function narrowTypeByAssertion(type: Type, expr: Expression): Type { const node = skipParentheses(expr); + if (node.kind === SyntaxKind.FalseKeyword) { + return unreachableNeverType; + } if (node.kind === SyntaxKind.BinaryExpression) { if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { return narrowTypeByAssertion(narrowTypeByAssertion(type, (node).left), (node).right); @@ -19068,7 +19096,7 @@ namespace ts { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : + predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : type; return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); }