diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 455600290e6..b50ad53901e 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -431,34 +431,45 @@ function voidFunctionParams( return voidReturnIndices; } -// Returns true if given type is a void-returning function. -function isVoidReturningFunctionType( +/** + * @returns Whether any call signature of the type has a thenable return type. + */ +function anySignatureIsThenableType( checker: ts.TypeChecker, node: ts.Node, type: ts.Type, ): boolean { - for (const subType of tsutils.unionTypeParts(type)) { - for (const signature of subType.getCallSignatures()) { - const returnType = signature.getReturnType(); + for (const signature of type.getCallSignatures()) { + const returnType = signature.getReturnType(); + if (tsutils.isThenableType(checker, node, returnType)) { + return true; + } + } - // If a certain positional argument accepts both thenable and void returns, - // a promise-returning function is valid - if (tsutils.isThenableType(checker, node, returnType)) { - return false; - } + return false; +} - if (tsutils.isTypeFlagSet(returnType, ts.TypeFlags.Void)) { - return true; - } +/** + * @returns Whether type is a thenable-returning function. + */ +function isThenableReturningFunctionType( + checker: ts.TypeChecker, + node: ts.Node, + type: ts.Type, +): boolean { + for (const subType of tsutils.unionTypeParts(type)) { + if (anySignatureIsThenableType(checker, node, subType)) { + return true; } } + return false; } /** * @returns Whether type is a void-returning function. */ -function isThenableReturningFunctionType( +function isVoidReturningFunctionType( checker: ts.TypeChecker, node: ts.Node, type: ts.Type, @@ -466,26 +477,29 @@ function isThenableReturningFunctionType( for (const subType of tsutils.unionTypeParts(type)) { for (const signature of subType.getCallSignatures()) { const returnType = signature.getReturnType(); + + // If a certain positional argument accepts both thenable and void returns, + // a promise-returning function is valid if (tsutils.isThenableType(checker, node, returnType)) { + return false; + } + + if (tsutils.isTypeFlagSet(returnType, ts.TypeFlags.Void)) { return true; } } } - return false; } -// Returns true if the expression is a function that returns a thenable +/** + * @returns Whether expression is a function that returns a thenable. + */ function returnsThenable(checker: ts.TypeChecker, node: ts.Node): boolean { const type = checker.getApparentType(checker.getTypeAtLocation(node)); - for (const subType of tsutils.unionTypeParts(type)) { - for (const signature of subType.getCallSignatures()) { - const returnType = signature.getReturnType(); - if (tsutils.isThenableType(checker, node, returnType)) { - return true; - } - } + if (anySignatureIsThenableType(checker, node, type)) { + return true; } return false;