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 fb8ad9a7ffc..e63d3d351a2 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -84,6 +84,20 @@ node.addEventListener('click', function() {}); const foo = arr.map(i => i * i); ``` +### allowTypedFunctionExpressions + +Examples of additional **correct** code for this rule with `{ allowTypedFunctionExpressions: true }`: + +```ts +type FuncType = () => string; + +let arrowFn: FuncType = () => 'test'; + +let funcExpr: FuncType = function() { + return 'test'; +}; +``` + ## When Not To Use It If you don't wish to prevent calling code from using function return values in unexpected ways, then 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 e4f5dd46a3c..d767959c29f 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -4,6 +4,7 @@ import * as util from '../util'; type Options = [ { allowExpressions?: boolean; + allowTypedFunctionExpressions?: boolean; } ]; type MessageIds = 'missingReturnType'; @@ -28,6 +29,9 @@ export default util.createRule({ allowExpressions: { type: 'boolean', }, + allowTypedFunctionExpressions: { + type: 'boolean', + }, }, additionalProperties: false, }, @@ -36,27 +40,41 @@ export default util.createRule({ defaultOptions: [ { allowExpressions: true, + allowTypedFunctionExpressions: false, }, ], create(context, [options]) { /** - * Checks if the parent of a function expression is a constructor. - * @param parent The parent of a function expression node + * Checks if a node is a constructor. + * @param node The node to check + */ + function isConstructor(node: TSESTree.Node): boolean { + return ( + node.type === AST_NODE_TYPES.MethodDefinition && + node.kind === 'constructor' + ); + } + + /** + * Checks if a node is a setter. + * @param parent The node to check */ - function isConstructor(parent: TSESTree.Node): boolean { + function isSetter(node: TSESTree.Node): boolean { return ( - parent.type === AST_NODE_TYPES.MethodDefinition && - parent.kind === 'constructor' + node.type === AST_NODE_TYPES.MethodDefinition && node.kind === 'set' ); } /** - * Checks if the parent of a function expression is a setter. - * @param parent The parent of a function expression node + * Checks if a node is a variable declarator with a type annotation. + * @param node The node to check */ - function isSetter(parent: TSESTree.Node): boolean { + function isVariableDeclaratorWithTypeAnnotation( + node: TSESTree.Node, + ): boolean { return ( - parent.type === AST_NODE_TYPES.MethodDefinition && parent.kind === 'set' + node.type === AST_NODE_TYPES.VariableDeclarator && + !!node.id.typeAnnotation ); } @@ -103,6 +121,14 @@ export default util.createRule({ return; } + if ( + options.allowTypedFunctionExpressions && + node.parent && + isVariableDeclaratorWithTypeAnnotation(node.parent) + ) { + return; + } + checkFunctionReturnType(node); } 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 0abc6000f18..932e50e9714 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 @@ -92,6 +92,28 @@ function test() { }, ], }, + { + filename: 'test.ts', + code: ` +var arrowFn: Foo = () => 'test'; + `, + options: [ + { + allowTypedFunctionExpressions: true, + }, + ], + }, + { + filename: 'test.ts', + code: ` +var funcExpr: Foo = function() { return 'test'; }; + `, + options: [ + { + allowTypedFunctionExpressions: true, + }, + ], + }, ], invalid: [ { @@ -188,5 +210,29 @@ class Test { }, ], }, + { + filename: 'test.ts', + code: `var arrowFn = () => 'test';`, + options: [{ allowTypedFunctionExpressions: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 1, + column: 15, + }, + ], + }, + { + filename: 'test.ts', + code: `var funcExpr = function() { return 'test'; };`, + options: [{ allowTypedFunctionExpressions: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 1, + column: 16, + }, + ], + }, ], });