@@ -37400,33 +37400,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37400
37400
}
37401
37401
37402
37402
function getTypePredicateFromBody(func: FunctionLikeDeclaration): TypePredicate | undefined {
37403
- switch (func.kind) {
37404
- case SyntaxKind.Constructor:
37405
- case SyntaxKind.GetAccessor:
37406
- case SyntaxKind.SetAccessor:
37407
- return undefined;
37403
+ if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.SetAccessor) {
37404
+ return undefined;
37408
37405
}
37409
- const functionFlags = getFunctionFlags(func);
37410
- if (functionFlags !== FunctionFlags.Normal || func.parameters.length === 0) return undefined;
37411
37406
37412
- // Only attempt to infer a type predicate if there's exactly one return.
37413
- let singleReturn: Expression | undefined;
37414
- let singleReturnStatement: ReturnStatement | undefined;
37415
- if (func.body && func.body.kind !== SyntaxKind.Block) {
37416
- singleReturn = func.body; // arrow function
37417
- }
37418
- else {
37419
- if (functionHasImplicitReturn(func)) return undefined;
37407
+ // Only a single-argument function can be inferred to be a type predicate
37408
+ if (func.parameters.length !== 1) return undefined;
37420
37409
37421
- const bailedEarly = forEachReturnStatement(func.body as Block, returnStatement => {
37422
- if (singleReturn || !returnStatement.expression) return true;
37423
- singleReturnStatement = returnStatement;
37424
- singleReturn = returnStatement.expression;
37425
- });
37426
- if (bailedEarly || !singleReturn) return undefined;
37410
+ // The body must be an expression, or a block containing a lone return statement
37411
+ if (!func.body) return undefined;
37412
+
37413
+ let returnExpression: Expression | undefined;
37414
+ if (func.body.kind === SyntaxKind.Block) {
37415
+ const body = func.body as Block;
37416
+ if ((body.statements.length !== 1) || (body.statements[0].kind !== SyntaxKind.ReturnStatement)) return undefined;
37417
+ returnExpression = (body.statements[0] as ReturnStatement).expression;
37418
+ } else {
37419
+ returnExpression = func.body;
37427
37420
}
37421
+ if (!returnExpression) return undefined;
37428
37422
37429
- const predicate = checkIfExpressionRefinesAnyParameter(singleReturn);
37423
+ const functionFlags = getFunctionFlags(func);
37424
+ if (functionFlags !== FunctionFlags.Normal) return undefined;
37425
+
37426
+ const predicate = checkIfExpressionRefinesAnyParameter(returnExpression);
37430
37427
if (predicate) {
37431
37428
const [i, type] = predicate;
37432
37429
const param = func.parameters[i];
@@ -37474,17 +37471,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37474
37471
};
37475
37472
const falseSubtype = getFlowTypeOfReference(param.name, trueType, trueType, func, falseCondition);
37476
37473
if (!isTypeIdenticalTo(falseSubtype, neverType)) return undefined;
37477
-
37478
- // the parameter type may already have been narrowed due to an assertion.
37479
- // There's no precise way to represent an assertion that's also a predicate. Best not to try.
37480
- // We do this check last since it's unlikely to filter out many possible predicates.
37481
- if (singleReturnStatement?.flowNode) {
37482
- const typeAtReturn = getFlowTypeOfReference(param.name, initType, initType, func, singleReturnStatement?.flowNode);
37483
- if (typeAtReturn !== initType) {
37484
- return undefined;
37485
- }
37486
- }
37487
-
37488
37474
return trueType;
37489
37475
}
37490
37476
}
0 commit comments