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 b6f37038aba..46cd2b86077 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -98,6 +98,23 @@ let arrowFn: FuncType = () => 'test'; let funcExpr: FuncType = function() { return 'test'; }; + +let asTyped = (() => '') as () => string; + +interface ObjectType { + foo(): number; +} +let objectProp: ObjectType = { + foo: () => 1, +}; + +interface ObjectType { + foo(): number; +} + +let asObjectProp = { + foo: () => 1, +} as ObjectType; ``` ## When Not To Use It 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 0d9f9304d2a..9186ef3cab6 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -57,7 +57,6 @@ export default util.createRule({ /** * Checks if a node is a setter. - * @param parent The node to check */ function isSetter(node: TSESTree.Node): boolean { return ( @@ -67,7 +66,6 @@ export default util.createRule({ /** * Checks if a node is a variable declarator with a type annotation. - * @param node The node to check */ function isVariableDeclaratorWithTypeAnnotation( node: TSESTree.Node, @@ -78,6 +76,38 @@ export default util.createRule({ ); } + /** + * Checks if a node belongs to: + * const x: Foo = { prop: () => {} } + */ + function isPropertyOfObjectVariableDeclaratorWithTypeAnnotation( + node: TSESTree.Node, + ): boolean { + let parent = node.parent; + if (!parent || parent.type !== AST_NODE_TYPES.Property) { + return false; + } + parent = parent.parent; + if (!parent || parent.type !== AST_NODE_TYPES.ObjectExpression) { + return false; + } + parent = parent.parent; + return !!parent && isVariableDeclaratorWithTypeAnnotation(parent); + } + + function isPropertyOfObjectInAsExpression(node: TSESTree.Node): boolean { + let parent = node.parent; + if (!parent || parent.type !== AST_NODE_TYPES.Property) { + return false; + } + parent = parent.parent; + if (!parent || parent.type !== AST_NODE_TYPES.ObjectExpression) { + return false; + } + parent = parent.parent; + return !!parent && parent.type === AST_NODE_TYPES.TSAsExpression; + } + /** * Checks if a function declaration/expression has a return type. * @param node The node representing a function. @@ -117,15 +147,15 @@ export default util.createRule({ * @param {ASTNode} node The node representing a function. */ function checkFunctionExpressionReturnType( - node: - | TSESTree.ArrowFunctionExpression - | TSESTree.FunctionDeclaration - | TSESTree.FunctionExpression, + node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): void { if ( options.allowTypedFunctionExpressions && node.parent && - isVariableDeclaratorWithTypeAnnotation(node.parent) + (isVariableDeclaratorWithTypeAnnotation(node.parent) || + isPropertyOfObjectVariableDeclaratorWithTypeAnnotation(node) || + node.parent.type === AST_NODE_TYPES.TSAsExpression || + isPropertyOfObjectInAsExpression(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 45ff620d616..4c242b484cc 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 @@ -120,6 +120,29 @@ var funcExpr: Foo = function() { return 'test'; }; }, ], }, + { + filename: 'test.ts', + code: `const x = (() => {}) as Foo`, + options: [{ allowTypedFunctionExpressions: true }], + }, + { + filename: 'test.ts', + code: ` +const x = { + foo: () => {}, +} as Foo + `, + options: [{ allowTypedFunctionExpressions: true }], + }, + { + filename: 'test.ts', + code: ` +const x: Foo = { + foo: () => {}, +} + `, + options: [{ allowTypedFunctionExpressions: true }], + }, ], invalid: [ { @@ -260,5 +283,49 @@ class Test { }, ], }, + + { + filename: 'test.ts', + code: `const x = (() => {}) as Foo`, + options: [{ allowTypedFunctionExpressions: false }], + errors: [ + { + messageId: 'missingReturnType', + line: 1, + }, + ], + }, + { + filename: 'test.ts', + code: ` +interface Foo {} +const x = { + foo: () => {}, +} as Foo + `, + options: [{ allowTypedFunctionExpressions: false }], + errors: [ + { + messageId: 'missingReturnType', + line: 4, + }, + ], + }, + { + filename: 'test.ts', + code: ` +interface Foo {} +const x: Foo = { + foo: () => {}, +} + `, + options: [{ allowTypedFunctionExpressions: false }], + errors: [ + { + messageId: 'missingReturnType', + line: 4, + }, + ], + }, ], });