From 8141f01db8fa0c7b75fa1ef989ea0b8a4635fe0c Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 24 Jul 2019 16:45:14 -0700 Subject: [PATCH] feat(eslint-plugin): add support for object props in CallExpressions (#728) --- .../rules/explicit-function-return-type.md | 7 + .../rules/explicit-function-return-type.ts | 19 +-- .../explicit-function-return-type.test.ts | 143 ++++++++++++------ 3 files changed, 116 insertions(+), 53 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 9aacb0acafc..01755e39540 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -141,6 +141,13 @@ let objectPropCast = { declare functionWithArg(arg: () => number); functionWithArg(() => 1); + +declare functionWithObjectArg(arg: { meth: () => number }); +functionWithObjectArg({ + meth() { + return 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 6d0625cd5cd..8e02b893f64 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -118,20 +118,20 @@ export default util.createRule({ * `const x = { prop: () => {} }` */ function isPropertyOfObjectWithType( - parent: TSESTree.Node | undefined, + property: TSESTree.Node | undefined, ): boolean { - if (!parent || parent.type !== AST_NODE_TYPES.Property) { + if (!property || property.type !== AST_NODE_TYPES.Property) { return false; } - parent = parent.parent; // this shouldn't happen, checking just in case + const objectExpr = property.parent; // this shouldn't happen, checking just in case /* istanbul ignore if */ if ( - !parent || - parent.type !== AST_NODE_TYPES.ObjectExpression + !objectExpr || + objectExpr.type !== AST_NODE_TYPES.ObjectExpression ) { return false; } - parent = parent.parent; // this shouldn't happen, checking just in case + const parent = objectExpr.parent; // this shouldn't happen, checking just in case /* istanbul ignore if */ if (!parent) { return false; } @@ -139,7 +139,8 @@ export default util.createRule({ return ( isTypeCast(parent) || isClassPropertyWithTypeAnnotation(parent) || - isVariableDeclaratorWithTypeAnnotation(parent) + isVariableDeclaratorWithTypeAnnotation(parent) || + isFunctionArgument(parent) ); } @@ -193,12 +194,12 @@ export default util.createRule({ */ function isFunctionArgument( parent: TSESTree.Node, - child: TSESTree.Node, + callee?: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): boolean { return ( parent.type === AST_NODE_TYPES.CallExpression && // make sure this isn't an IIFE - parent.callee !== child + parent.callee !== callee ); } 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 ddcf99e127a..72d64d2abe0 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 @@ -273,6 +273,32 @@ new Accumulator().accumulate(() => 1); }, ], }, + { + filename: 'test.ts', + code: ` +declare function foo(arg: { meth: () => number }): void +foo({ + meth() { + return 1; + }, +}) +foo({ + meth: function () { + return 1; + }, +}) +foo({ + meth: () => { + return 1; + }, +}) + `, + options: [ + { + allowTypedFunctionExpressions: true, + }, + ], + }, ], invalid: [ { @@ -281,7 +307,7 @@ new Accumulator().accumulate(() => 1); function test() { return; } - `, + `, errors: [ { messageId: 'missingReturnType', @@ -296,7 +322,7 @@ function test() { var fn = function() { return 1; }; - `, + `, errors: [ { messageId: 'missingReturnType', @@ -309,7 +335,7 @@ var fn = function() { filename: 'test.ts', code: ` var arrowFn = () => 'test'; - `, + `, errors: [ { messageId: 'missingReturnType', @@ -332,7 +358,7 @@ class Test { } arrow = () => 'arrow'; } - `, + `, errors: [ { messageId: 'missingReturnType', @@ -353,21 +379,23 @@ class Test { }, { filename: 'test.ts', - code: `function test() { - return; - }`, + code: ` +function test() { + return; +} + `, options: [{ allowExpressions: true }], errors: [ { messageId: 'missingReturnType', - line: 1, + line: 2, column: 1, }, ], }, { filename: 'test.ts', - code: `const foo = () => {};`, + code: 'const foo = () => {};', options: [{ allowExpressions: true }], errors: [ { @@ -379,7 +407,7 @@ class Test { }, { filename: 'test.ts', - code: `const foo = function() {};`, + code: 'const foo = function() {};', options: [{ allowExpressions: true }], errors: [ { @@ -391,7 +419,7 @@ class Test { }, { filename: 'test.ts', - code: `var arrowFn = () => 'test';`, + code: "var arrowFn = () => 'test';", options: [{ allowTypedFunctionExpressions: true }], errors: [ { @@ -403,7 +431,7 @@ class Test { }, { filename: 'test.ts', - code: `var funcExpr = function() { return 'test'; };`, + code: "var funcExpr = function() { return 'test'; };", options: [{ allowTypedFunctionExpressions: true }], errors: [ { @@ -416,7 +444,7 @@ class Test { { filename: 'test.ts', - code: `const x = (() => {}) as Foo`, + code: 'const x = (() => {}) as Foo', options: [{ allowTypedFunctionExpressions: false }], errors: [ { @@ -459,84 +487,72 @@ const x: Foo = { }, { filename: 'test.ts', - code: ` -() => () => {}; - `, + code: '() => () => {};', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 7, }, ], }, { filename: 'test.ts', - code: ` -() => function () {}; - `, + code: '() => function () {};', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 7, }, ], }, { filename: 'test.ts', - code: ` -() => { return () => {} }; - `, + code: '() => { return () => {} };', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 16, }, ], }, { filename: 'test.ts', - code: ` -() => { return function () {} }; - `, + code: '() => { return function () {} };', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 16, }, ], }, { filename: 'test.ts', - code: ` -function fn() { return () => {} }; - `, + code: 'function fn() { return () => {} };', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 24, }, ], }, { filename: 'test.ts', - code: ` -function fn() { return function () {} }; - `, + code: 'function fn() { return function () {} };', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 24, }, ], @@ -566,14 +582,12 @@ function FunctionDeclaration() { }, { filename: 'test.ts', - code: ` -() => () => { return () => { return; } }; - `, + code: '() => () => { return () => { return; } };', options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', - line: 2, + line: 1, column: 22, }, ], @@ -643,10 +657,41 @@ new Accumulator().accumulate(() => 1); }, ], }, + { + filename: 'test.ts', + code: '(() => true)()', + options: [ + { + allowTypedFunctionExpressions: false, + }, + ], + errors: [ + { + messageId: 'missingReturnType', + line: 1, + column: 2, + }, + ], + }, { filename: 'test.ts', code: ` -(() => true)() +declare function foo(arg: { meth: () => number }): void +foo({ + meth() { + return 1; + }, +}) +foo({ + meth: function () { + return 1; + }, +}) +foo({ + meth: () => { + return 1; + }, +}) `, options: [ { @@ -656,8 +701,18 @@ new Accumulator().accumulate(() => 1); errors: [ { messageId: 'missingReturnType', - line: 2, - column: 2, + line: 4, + column: 7, + }, + { + messageId: 'missingReturnType', + line: 9, + column: 9, + }, + { + messageId: 'missingReturnType', + line: 14, + column: 9, }, ], },