From 68ef0b1f7ca5ee87500eb0c8bd0cbd2e604861c9 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Thu, 16 May 2019 22:57:59 +0200 Subject: [PATCH 01/12] fix(eslint-plugin): explicit-function-return-type allowCurry (#193) --- .../rules/explicit-function-return-type.ts | 13 ++++++ .../explicit-function-return-type.test.ts | 40 +++++++++++++++++++ 2 files changed, 53 insertions(+) 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 be6bb14c4488..04550b253c19 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -8,6 +8,7 @@ type Options = [ { allowExpressions?: boolean; allowTypedFunctionExpressions?: boolean; + allowCurrying?: boolean; } ]; type MessageIds = 'missingReturnType'; @@ -35,6 +36,9 @@ export default util.createRule({ allowTypedFunctionExpressions: { type: 'boolean', }, + allowCurrying: { + type: 'boolean', + }, }, additionalProperties: false, }, @@ -44,6 +48,7 @@ export default util.createRule({ { allowExpressions: false, allowTypedFunctionExpressions: false, + allowCurrying: false, }, ], create(context, [options]) { @@ -188,6 +193,14 @@ export default util.createRule({ ) { return; } + + if ( + options.allowCurrying && + node.type === AST_NODE_TYPES.ArrowFunctionExpression && + node.body.type === AST_NODE_TYPES.ArrowFunctionExpression + ) { + 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 936b300134bf..8c9ab09b9f20 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 @@ -32,6 +32,13 @@ var arrowFn = (): string => 'test'; { filename: 'test.ts', code: ` +var curryFn = (bar: string) => (baz: string): string => bar + baz; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` class Test { constructor() {} get prop(): number { @@ -228,6 +235,39 @@ var arrowFn = () => 'test'; { filename: 'test.ts', code: ` +var curryFn = (bar: string) => (baz: string) => bar + baz; + `, + options: [{ allowCurrying: false }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 15, + }, + { + messageId: 'missingReturnType', + line: 2, + column: 32, + }, + ], + }, + { + filename: 'test.ts', + code: ` +var curryFn = (bar: string) => (baz: string) => bar + baz; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 32, + }, + ], + }, + { + filename: 'test.ts', + code: ` class Test { constructor() {} get prop() { From f90639737b875db93d8a0814fa013a90c12e02ae Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Thu, 16 May 2019 23:45:28 +0200 Subject: [PATCH 02/12] chore: added allowCurrying to docs --- .../docs/rules/explicit-function-return-type.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 2812023ffba9..b73f6b03ae76 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -67,11 +67,14 @@ type Options = { allowExpressions?: boolean; // if true, type annotations are also allowed on the variable of a function expression rather than on the function directly. allowTypedFunctionExpressions?: boolean; + // if true, only arrow functions which does not return an arrow function will be checked + allowCurrying?: boolean; }; const defaults = { allowExpressions: false, allowTypedFunctionExpressions: false, + allowCurrying: false, }; ``` @@ -137,6 +140,20 @@ let objectPropCast = { }; ``` +### allowCurrying + +Examples of **incorrect** code for this rule with `{ allowCurrying: true }`: + +```ts +var curryFn = (bar: string) => (baz: string) => bar + baz; +``` + +Examples of **correct** code for this rule with `{ allowCurrying: true }`: + +```ts +var curryFn = (bar: string) => (baz: string): string => bar + baz; +``` + ## When Not To Use It If you don't wish to prevent calling code from using function return values in unexpected ways, then From 8e1a82f3e300be73974791b4f095fbfd3643239c Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Fri, 17 May 2019 00:20:24 +0200 Subject: [PATCH 03/12] chore: more logical tests and docs --- .../docs/rules/explicit-function-return-type.md | 4 ++-- .../rules/explicit-function-return-type.test.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 8 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 b73f6b03ae76..358c20689424 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -145,13 +145,13 @@ let objectPropCast = { Examples of **incorrect** code for this rule with `{ allowCurrying: true }`: ```ts -var curryFn = (bar: string) => (baz: string) => bar + baz; +var curryFn = (x: number) => (y: number) => x + y; ``` Examples of **correct** code for this rule with `{ allowCurrying: true }`: ```ts -var curryFn = (bar: string) => (baz: string): string => bar + baz; +var curryFn = (x: number) => (y: number): number => x + y; ``` ## When Not To Use It 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 8c9ab09b9f20..0dbedf083d9b 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 @@ -32,7 +32,7 @@ var arrowFn = (): string => 'test'; { filename: 'test.ts', code: ` -var curryFn = (bar: string) => (baz: string): string => bar + baz; +var curriedAddFn = (x: int) => (y: int): int => x + y; `, options: [{ allowCurrying: true }], }, @@ -235,33 +235,33 @@ var arrowFn = () => 'test'; { filename: 'test.ts', code: ` -var curryFn = (bar: string) => (baz: string) => bar + baz; +var curriedAddFn = (x: number) => (y: number) => x + y; `, options: [{ allowCurrying: false }], errors: [ { messageId: 'missingReturnType', line: 2, - column: 15, + column: 20, }, { messageId: 'missingReturnType', line: 2, - column: 32, + column: 35, }, ], }, { filename: 'test.ts', code: ` -var curryFn = (bar: string) => (baz: string) => bar + baz; +var curriedAddFn = (x: number) => (y: number) => x + y; `, options: [{ allowCurrying: true }], errors: [ { messageId: 'missingReturnType', line: 2, - column: 32, + column: 35, }, ], }, From 0c8af622b24b1b30baed94e78cafd3daa3a5a6ec Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Fri, 17 May 2019 00:25:51 +0200 Subject: [PATCH 04/12] chore: moved tests after existing tests --- .../rules/explicit-function-return-type.md | 4 +- .../explicit-function-return-type.test.ts | 80 +++++++++---------- 2 files changed, 42 insertions(+), 42 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 358c20689424..86f12e470a4a 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -145,13 +145,13 @@ let objectPropCast = { Examples of **incorrect** code for this rule with `{ allowCurrying: true }`: ```ts -var curryFn = (x: number) => (y: number) => x + y; +var curriedAddFn = (x: number) => (y: number) => x + y; ``` Examples of **correct** code for this rule with `{ allowCurrying: true }`: ```ts -var curryFn = (x: number) => (y: number): number => x + y; +var curriedAddFn = (x: number) => (y: number): number => x + y; ``` ## When Not To Use It 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 0dbedf083d9b..aeee354fd944 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 @@ -32,13 +32,6 @@ var arrowFn = (): string => 'test'; { filename: 'test.ts', code: ` -var curriedAddFn = (x: int) => (y: int): int => x + y; - `, - options: [{ allowCurrying: true }], - }, - { - filename: 'test.ts', - code: ` class Test { constructor() {} get prop(): number { @@ -187,6 +180,13 @@ const myObj = { }; `, }, + { + filename: 'test.ts', + code: ` +var curriedAddFn = (x: int) => (y: int): int => x + y; + `, + options: [{ allowCurrying: true }], + }, ], invalid: [ { @@ -235,39 +235,6 @@ var arrowFn = () => 'test'; { filename: 'test.ts', code: ` -var curriedAddFn = (x: number) => (y: number) => x + y; - `, - options: [{ allowCurrying: false }], - errors: [ - { - messageId: 'missingReturnType', - line: 2, - column: 20, - }, - { - messageId: 'missingReturnType', - line: 2, - column: 35, - }, - ], - }, - { - filename: 'test.ts', - code: ` -var curriedAddFn = (x: number) => (y: number) => x + y; - `, - options: [{ allowCurrying: true }], - errors: [ - { - messageId: 'missingReturnType', - line: 2, - column: 35, - }, - ], - }, - { - filename: 'test.ts', - code: ` class Test { constructor() {} get prop() { @@ -404,5 +371,38 @@ const x: Foo = { }, ], }, + { + filename: 'test.ts', + code: ` +var curriedAddFn = (x: number) => (y: number) => x + y; + `, + options: [{ allowCurrying: false }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 20, + }, + { + messageId: 'missingReturnType', + line: 2, + column: 35, + }, + ], + }, + { + filename: 'test.ts', + code: ` +var curriedAddFn = (x: number) => (y: number) => x + y; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 35, + }, + ], + }, ], }); From 8b52be01e329a3b7f30fafca82bf27dc1623a389 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Mon, 20 May 2019 23:18:40 +0200 Subject: [PATCH 05/12] Corrected int => number --- .../tests/rules/explicit-function-return-type.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 aeee354fd944..24006348a70b 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 @@ -183,7 +183,7 @@ const myObj = { { filename: 'test.ts', code: ` -var curriedAddFn = (x: int) => (y: int): int => x + y; +var curriedAddFn = (x: number) => (y: number): number => x + y; `, options: [{ allowCurrying: true }], }, From 4101273c86e186dc117fca80298fb020e658af66 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Mon, 20 May 2019 23:34:28 +0200 Subject: [PATCH 06/12] Removed irrelevant test arguments for better clarity --- .../tests/rules/explicit-function-return-type.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 24006348a70b..96c825249ffa 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 @@ -183,7 +183,7 @@ const myObj = { { filename: 'test.ts', code: ` -var curriedAddFn = (x: number) => (y: number): number => x + y; +var curriedAddFn = () => (): number => {}; `, options: [{ allowCurrying: true }], }, @@ -393,14 +393,14 @@ var curriedAddFn = (x: number) => (y: number) => x + y; { filename: 'test.ts', code: ` -var curriedAddFn = (x: number) => (y: number) => x + y; +var curriedAddFn = () => () => {}; `, options: [{ allowCurrying: true }], errors: [ { messageId: 'missingReturnType', line: 2, - column: 35, + column: 26, }, ], }, From bddedcc9d1950f7c1e746f2a9786014ac88b8083 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Tue, 21 May 2019 02:33:25 +0200 Subject: [PATCH 07/12] Made allowCurrying cover more cases as requested --- .../rules/explicit-function-return-type.ts | 56 ++++++- .../explicit-function-return-type.test.ts | 139 +++++++++++++++++- 2 files changed, 180 insertions(+), 15 deletions(-) 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 04550b253c19..06351a8ae204 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -143,6 +143,50 @@ export default util.createRule({ ); } + /** + * Checks if a function belongs to: + * `() => () => ...` + * `() => function () { ... }` + * `() => { return () => ... }` + * `() => { return function () { ... } }` + * `function fn() { return () => ... }` + * `function fn() { return function() { ... } }` + */ + function isCurrying({ + body, + }: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.FunctionExpression): boolean { + // Should always have a body; really checking just in case + /* istanbul ignore if */ if (!body) { + return false; + } + + // Body can be a single statement block + if ( + body.type === AST_NODE_TYPES.BlockStatement && + body.body.length === 1 + ) { + const [statement] = body.body; + + // Which is a return statement with an argument + if ( + statement.type === AST_NODE_TYPES.ReturnStatement && + !!statement.argument + ) { + // In which case we check that instead of original body + body = statement.argument; + } + } + + // Then, check if body is a function expression + return ( + body.type === AST_NODE_TYPES.ArrowFunctionExpression || + body.type === AST_NODE_TYPES.FunctionExpression + ); + } + /** * Checks if a function declaration/expression has a return type. */ @@ -152,6 +196,10 @@ export default util.createRule({ | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression, ): void { + if (options.allowCurrying && isCurrying(node)) { + return; + } + if ( node.returnType || isConstructor(node.parent) || @@ -193,14 +241,6 @@ export default util.createRule({ ) { return; } - - if ( - options.allowCurrying && - node.type === AST_NODE_TYPES.ArrowFunctionExpression && - node.body.type === AST_NODE_TYPES.ArrowFunctionExpression - ) { - 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 96c825249ffa..943ccbcf5520 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 @@ -183,7 +183,58 @@ const myObj = { { filename: 'test.ts', code: ` -var curriedAddFn = () => (): number => {}; +() => (): void => {}; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +() => function (): void {}; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +() => { return (): void => {} }; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +() => { return function (): void {} }; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +function fn() { return (): void => {} }; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +function fn() { return function (): void {} }; + `, + options: [{ allowCurrying: true }], + }, + { + filename: 'test.ts', + code: ` +function FunctionDeclaration() { + return function FunctionExpression_Within_FunctionDeclaration() { + return function FunctionExpression_Within_FunctionExpression() { + return () => { // ArrowFunctionExpression_Within_FunctionExpression + return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression + (): number => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + } + } + } +} `, options: [{ allowCurrying: true }], }, @@ -374,33 +425,107 @@ const x: Foo = { { filename: 'test.ts', code: ` -var curriedAddFn = (x: number) => (y: number) => x + y; +() => () => {}; `, - options: [{ allowCurrying: false }], + options: [{ allowCurrying: true }], errors: [ { messageId: 'missingReturnType', line: 2, - column: 20, + column: 7, }, + ], + }, + { + filename: 'test.ts', + code: ` +() => function () {}; + `, + options: [{ allowCurrying: true }], + errors: [ { messageId: 'missingReturnType', line: 2, - column: 35, + column: 7, }, ], }, { filename: 'test.ts', code: ` -var curriedAddFn = () => () => {}; +() => { return () => {} }; `, options: [{ allowCurrying: true }], errors: [ { messageId: 'missingReturnType', line: 2, - column: 26, + column: 16, + }, + ], + }, + { + filename: 'test.ts', + code: ` +() => { return function () {} }; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 16, + }, + ], + }, + { + filename: 'test.ts', + code: ` +function fn() { return () => {} }; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 24, + }, + ], + }, + { + filename: 'test.ts', + code: ` +function fn() { return function () {} }; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 24, + }, + ], + }, + { + filename: 'test.ts', + code: ` +function FunctionDeclaration() { + return function FunctionExpression_Within_FunctionDeclaration() { + return function FunctionExpression_Within_FunctionExpression() { + return () => { // ArrowFunctionExpression_Within_FunctionExpression + return () => // ArrowFunctionExpression_Within_ArrowFunctionExpression + () => 1 // ArrowFunctionExpression_Within_ArrowFunctionExpression_WithNoBody + } + } + } +} + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 7, + column: 11, }, ], }, From 45c6b13d7cce12ae3bfa59f8ff07b8757d0b3d56 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Tue, 21 May 2019 02:39:02 +0200 Subject: [PATCH 08/12] Updated allowCurrying documentation --- .../eslint-plugin/docs/rules/explicit-function-return-type.md | 4 ++-- 1 file changed, 2 insertions(+), 2 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 86f12e470a4a..c662293d027a 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -65,9 +65,9 @@ The rule accepts an options object with the following properties: type Options = { // if true, only functions which are part of a declaration will be checked allowExpressions?: boolean; - // if true, type annotations are also allowed on the variable of a function expression rather than on the function directly. + // if true, type annotations are also allowed on the variable of a function expression rather than on the function directly allowTypedFunctionExpressions?: boolean; - // if true, only arrow functions which does not return an arrow function will be checked + // if true, currying functions (those immediately returning another function expression) will not be checked allowCurrying?: boolean; }; From ea519d27f19262d49721d48621e8917b3b080d24 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Wed, 22 May 2019 20:55:53 +0200 Subject: [PATCH 09/12] Added example of regular curried function in documentation --- .../rules/explicit-function-return-type.md | 18 +++++++++++++++--- 1 file changed, 15 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 c662293d027a..02274da4e665 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -124,7 +124,7 @@ let funcExpr: FuncType = function() { }; let asTyped = (() => '') as () => string; -let caasTyped = <() => string>(() => ''); +let castTyped = <() => string>(() => ''); interface ObjectType { foo(): number; @@ -145,13 +145,25 @@ let objectPropCast = { Examples of **incorrect** code for this rule with `{ allowCurrying: true }`: ```ts -var curriedAddFn = (x: number) => (y: number) => x + y; +var curriedArrowFn = (x: number) => (y: number) => x + y; + +function curriedFunction(x: number) { + return function(y: number) { + return x + y; + }; +} ``` Examples of **correct** code for this rule with `{ allowCurrying: true }`: ```ts -var curriedAddFn = (x: number) => (y: number): number => x + y; +var curriedArrowFn = (x: number) => (y: number): number => x + y; + +function curriedFunction(x: number) { + return function(y: number): number { + return x + y; + }; +} ``` ## When Not To Use It From 7807778478dc2a8a25210a9e3711f27ac3703763 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Wed, 22 May 2019 22:32:58 +0200 Subject: [PATCH 10/12] Added tests to cover remaining branch in my code --- .../explicit-function-return-type.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 943ccbcf5520..5db73d046e37 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 @@ -238,6 +238,13 @@ function FunctionDeclaration() { `, options: [{ allowCurrying: true }], }, + { + filename: 'test.ts', + code: ` +() => () => { return (): void => { return; } }; + `, + options: [{ allowCurrying: true }], + }, ], invalid: [ { @@ -529,5 +536,19 @@ function FunctionDeclaration() { }, ], }, + { + filename: 'test.ts', + code: ` +() => () => { return () => { return; } }; + `, + options: [{ allowCurrying: true }], + errors: [ + { + messageId: 'missingReturnType', + line: 2, + column: 22, + }, + ], + }, ], }); From 1651e47ce68b9e9ea82297fe77916f908e448f79 Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Wed, 22 May 2019 23:07:37 +0200 Subject: [PATCH 11/12] Ignore impossible to hit else branch --- .../eslint-plugin/src/rules/explicit-function-return-type.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 06351a8ae204..3addbb6a0f92 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -222,7 +222,8 @@ export default util.createRule({ function checkFunctionExpressionReturnType( node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): void { - if (node.parent) { + // Should always have a parent; checking just in case + /* istanbul ignore else */ if (node.parent) { if (options.allowTypedFunctionExpressions) { if ( isTypeCast(node.parent) || From 3182953580376d943b6d3485c1ef8f8ca27ec2db Mon Sep 17 00:00:00 2001 From: Torleif Berger Date: Thu, 23 May 2019 18:50:09 +0200 Subject: [PATCH 12/12] Renamed option --- .../rules/explicit-function-return-type.md | 20 ++++++------ .../rules/explicit-function-return-type.ts | 21 ++++++------ .../explicit-function-return-type.test.ts | 32 +++++++++---------- 3 files changed, 38 insertions(+), 35 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 02274da4e665..a20aa83c7a5d 100644 --- a/packages/eslint-plugin/docs/rules/explicit-function-return-type.md +++ b/packages/eslint-plugin/docs/rules/explicit-function-return-type.md @@ -67,14 +67,14 @@ type Options = { allowExpressions?: boolean; // if true, type annotations are also allowed on the variable of a function expression rather than on the function directly allowTypedFunctionExpressions?: boolean; - // if true, currying functions (those immediately returning another function expression) will not be checked - allowCurrying?: boolean; + // if true, functions immediately returning another function expression will not be checked + allowHigherOrderFunctions?: boolean; }; const defaults = { allowExpressions: false, allowTypedFunctionExpressions: false, - allowCurrying: false, + allowHigherOrderFunctions: false, }; ``` @@ -140,26 +140,26 @@ let objectPropCast = { }; ``` -### allowCurrying +### allowHigherOrderFunctions -Examples of **incorrect** code for this rule with `{ allowCurrying: true }`: +Examples of **incorrect** code for this rule with `{ allowHigherOrderFunctions: true }`: ```ts -var curriedArrowFn = (x: number) => (y: number) => x + y; +var arrowFn = (x: number) => (y: number) => x + y; -function curriedFunction(x: number) { +function fn(x: number) { return function(y: number) { return x + y; }; } ``` -Examples of **correct** code for this rule with `{ allowCurrying: true }`: +Examples of **correct** code for this rule with `{ allowHigherOrderFunctions: true }`: ```ts -var curriedArrowFn = (x: number) => (y: number): number => x + y; +var arrowFn = (x: number) => (y: number): number => x + y; -function curriedFunction(x: number) { +function fn(x: number) { return function(y: number): number { return x + y; }; 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 3addbb6a0f92..876f42517d61 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -8,7 +8,7 @@ type Options = [ { allowExpressions?: boolean; allowTypedFunctionExpressions?: boolean; - allowCurrying?: boolean; + allowHigherOrderFunctions?: boolean; } ]; type MessageIds = 'missingReturnType'; @@ -36,7 +36,7 @@ export default util.createRule({ allowTypedFunctionExpressions: { type: 'boolean', }, - allowCurrying: { + allowHigherOrderFunctions: { type: 'boolean', }, }, @@ -48,7 +48,7 @@ export default util.createRule({ { allowExpressions: false, allowTypedFunctionExpressions: false, - allowCurrying: false, + allowHigherOrderFunctions: false, }, ], create(context, [options]) { @@ -152,7 +152,7 @@ export default util.createRule({ * `function fn() { return () => ... }` * `function fn() { return function() { ... } }` */ - function isCurrying({ + function doesImmediatelyReturnFunctionExpression({ body, }: | TSESTree.ArrowFunctionExpression @@ -163,24 +163,24 @@ export default util.createRule({ return false; } - // Body can be a single statement block + // Check if body is a block with a single statement if ( body.type === AST_NODE_TYPES.BlockStatement && body.body.length === 1 ) { const [statement] = body.body; - // Which is a return statement with an argument + // Check if that statement is a return statement with an argument if ( statement.type === AST_NODE_TYPES.ReturnStatement && !!statement.argument ) { - // In which case we check that instead of original body + // If so, check that returned argument as body body = statement.argument; } } - // Then, check if body is a function expression + // Check if the body being returned is a function expression return ( body.type === AST_NODE_TYPES.ArrowFunctionExpression || body.type === AST_NODE_TYPES.FunctionExpression @@ -196,7 +196,10 @@ export default util.createRule({ | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression, ): void { - if (options.allowCurrying && isCurrying(node)) { + if ( + options.allowHigherOrderFunctions && + doesImmediatelyReturnFunctionExpression(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 5db73d046e37..1b9209b7abf0 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 @@ -185,42 +185,42 @@ const myObj = { code: ` () => (): void => {}; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` () => function (): void {}; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` () => { return (): void => {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` () => { return function (): void {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` function fn() { return (): void => {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` function fn() { return function (): void {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', @@ -236,14 +236,14 @@ function FunctionDeclaration() { } } `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, { filename: 'test.ts', code: ` () => () => { return (): void => { return; } }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], }, ], invalid: [ @@ -434,7 +434,7 @@ const x: Foo = { code: ` () => () => {}; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -448,7 +448,7 @@ const x: Foo = { code: ` () => function () {}; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -462,7 +462,7 @@ const x: Foo = { code: ` () => { return () => {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -476,7 +476,7 @@ const x: Foo = { code: ` () => { return function () {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -490,7 +490,7 @@ const x: Foo = { code: ` function fn() { return () => {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -504,7 +504,7 @@ function fn() { return () => {} }; code: ` function fn() { return function () {} }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -527,7 +527,7 @@ function FunctionDeclaration() { } } `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType', @@ -541,7 +541,7 @@ function FunctionDeclaration() { code: ` () => () => { return () => { return; } }; `, - options: [{ allowCurrying: true }], + options: [{ allowHigherOrderFunctions: true }], errors: [ { messageId: 'missingReturnType',