From e0aeb184049084748e613b8d181d97ce19aaaa37 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 8 Jul 2019 07:31:27 -0700 Subject: [PATCH] feat(eslint-plugin): [explicit-function-return-type] add handling for usage as arguments (#680) --- .../rules/explicit-function-return-type.md | 3 + .../rules/explicit-function-return-type.ts | 18 ++- .../explicit-function-return-type.test.ts | 119 ++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md index a20aa83c7a5..9aacb0acafc 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -138,6 +138,9 @@ let objectPropAs = { let objectPropCast = { foo: () => 1, }; + +declare functionWithArg(arg: () => number); +functionWithArg(() => 1); ``` ### allowHigherOrderFunctions diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index 876f42517d6..d5176a43af5 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -187,6 +187,21 @@ export default util.createRule({ ); } + /** + * Checks if a node belongs to: + * `foo(() => 1)` + */ + function isFunctionArgument( + parent: TSESTree.Node, + child: TSESTree.Node, + ): boolean { + return ( + parent.type === AST_NODE_TYPES.CallExpression && + // make sure this isn't an IIFE + parent.callee !== child + ); + } + /** * Checks if a function declaration/expression has a return type. */ @@ -232,7 +247,8 @@ export default util.createRule({ isTypeCast(node.parent) || isVariableDeclaratorWithTypeAnnotation(node.parent) || isClassPropertyWithTypeAnnotation(node.parent) || - isPropertyOfObjectWithType(node.parent) + isPropertyOfObjectWithType(node.parent) || + isFunctionArgument(node.parent, node) ) { return; } diff --git a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts index 1b9209b7abf..eb67f620be1 100644 --- a/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-function-return-type.test.ts @@ -245,6 +245,42 @@ function FunctionDeclaration() { `, options: [{ allowHigherOrderFunctions: true }], }, + // https://github.com/typescript-eslint/typescript-eslint/issues/679 + { + filename: 'test.ts', + code: ` +declare function foo(arg: () => void): void +foo(() => 1) +foo(() => {}) +foo(() => null) +foo(() => true) +foo(() => '') + `, + options: [ + { + allowTypedFunctionExpressions: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +class Accumulator { + private count: number = 0; + + public accumulate(fn: () => number): void { + this.count += fn(); + } +} + +new Accumulator().accumulate(() => 1); + `, + options: [ + { + allowTypedFunctionExpressions: true, + }, + ], + }, ], invalid: [ { @@ -550,5 +586,88 @@ function FunctionDeclaration() { }, ], }, + // https://github.com/typescript-eslint/typescript-eslint/issues/679 + { + filename: 'test.ts', + code: ` +declare function foo(arg: () => void): void +foo(() => 1) +foo(() => {}) +foo(() => null) +foo(() => true) +foo(() => '') + `, + options: [ + { + allowTypedFunctionExpressions: false, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 3, + }, + { + messageId: 'missingReturnType', + line: 4, + }, + { + messageId: 'missingReturnType', + line: 5, + }, + { + messageId: 'missingReturnType', + line: 6, + }, + { + messageId: 'missingReturnType', + line: 7, + }, + ], + }, + { + filename: 'test.ts', + code: ` +class Accumulator { + private count: number = 0; + + public accumulate(fn: () => number): void { + this.count += fn(); + } +} + +new Accumulator().accumulate(() => 1); + `, + options: [ + { + allowTypedFunctionExpressions: false, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 10, + column: 30, + }, + ], + }, + { + filename: 'test.ts', + code: ` +(() => true)() + `, + options: [ + { + allowTypedFunctionExpressions: false, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 2, + }, + ], + }, ], });