From 8a73cee63629dd6b9cf9312790c0dde3a45958b5 Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Tue, 12 Feb 2019 11:02:46 +0100 Subject: [PATCH] feat(eslint-plugin): allow explicit variable type with arrow functions Fixes #149 --- .../rules/explicit-function-return-type.md | 14 ++++++ .../rules/explicit-function-return-type.ts | 26 +++++++++-- .../explicit-function-return-type.test.ts | 46 +++++++++++++++++++ 3 files changed, 83 insertions(+), 3 deletions(-) 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 fb8ad9a7ffc8..e63d3d351a25 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 0a7a0db73995..3403124d9c65 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -9,6 +9,7 @@ import * as util from '../util'; type Options = [ { allowExpressions?: boolean; + allowTypedFunctionExpressions?: boolean; } ]; type MessageIds = 'missingReturnType'; @@ -32,6 +33,9 @@ export default util.createRule({ properties: { allowExpressions: { type: 'boolean' + }, + allowTypedFunctionExpressions: { + type: 'boolean' } }, additionalProperties: false @@ -40,7 +44,8 @@ export default util.createRule({ }, defaultOptions: [ { - allowExpressions: true + allowExpressions: true, + allowTypedFunctionExpressions: false } ], create(context, [options]) { @@ -65,6 +70,17 @@ export default util.createRule({ ); } + /** + * Checks if the parent of a function expression has a type annotation. + * @param parent The parent of a function expression node + */ + function hasTypeAnnotation(parent: TSESTree.Node): boolean { + return ( + parent.type === AST_NODE_TYPES.VariableDeclarator && + !!parent.id.typeAnnotation + ); + } + /** * Checks if a function declaration/expression has a return type. * @param node The node representing a function. @@ -75,11 +91,15 @@ export default util.createRule({ | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression ): void { + if (node.returnType || !node.parent) return; + + const checkTypeAnnotation = + options.allowTypedFunctionExpressions && hasTypeAnnotation(node.parent); + if ( - !node.returnType && - node.parent && !isConstructor(node.parent) && !isSetter(node.parent) && + !checkTypeAnnotation && util.isTypeScriptFile(context.getFilename()) ) { context.report({ 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 3348942e4d06..7a02e2b65701 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 @@ -91,6 +91,28 @@ function test() { allowExpressions: true } ] + }, + { + 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: [ @@ -187,6 +209,30 @@ class Test { column: 13 } ] + }, + { + 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 + } + ] } ] });