From e8a3aa92fb4aea9bca562a480cf37b05ab0ada1d Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Tue, 25 Feb 2025 18:40:39 +0200 Subject: [PATCH 1/6] initial implementation --- .../rules/explicit-module-boundary-types.ts | 29 +++++++++- .../explicit-module-boundary-types.test.ts | 58 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index c8a627e7aca5..8b832713e49f 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -9,7 +9,12 @@ import type { FunctionNode, } from '../util/explicitReturnTypeUtils'; -import { createRule, isFunction, isStaticMemberAccessOfValue } from '../util'; +import { + createRule, + hasOverloadSignatures, + isFunction, + isStaticMemberAccessOfValue, +} from '../util'; import { ancestorHasReturnType, checkFunctionExpressionReturnType, @@ -25,6 +30,7 @@ export type Options = [ allowedNames?: string[]; allowHigherOrderFunctions?: boolean; allowTypedFunctionExpressions?: boolean; + allowImplicitReturnTypeForOverloadImplementations?: boolean; }, ]; export type MessageIds = @@ -82,6 +88,11 @@ export default createRule({ 'You must still type the parameters of the function.', ].join('\n'), }, + allowImplicitReturnTypeForOverloadImplementations: { + type: 'boolean', + description: + 'Whether to ignore missing return type annotations on functions with overload signatures.', + }, allowTypedFunctionExpressions: { type: 'boolean', description: @@ -97,6 +108,7 @@ export default createRule({ allowDirectConstAssertionInArrowFunctions: true, allowedNames: [], allowHigherOrderFunctions: true, + allowImplicitReturnTypeForOverloadImplementations: false, allowTypedFunctionExpressions: true, }, ], @@ -456,6 +468,14 @@ export default createRule({ return; } + if ( + options.allowImplicitReturnTypeForOverloadImplementations && + node.parent.type === AST_NODE_TYPES.MethodDefinition && + hasOverloadSignatures(node.parent, context) + ) { + return; + } + checkFunctionExpressionReturnType( { node, returns }, options, @@ -485,6 +505,13 @@ export default createRule({ return; } + if ( + options.allowImplicitReturnTypeForOverloadImplementations && + hasOverloadSignatures(node, context) + ) { + return; + } + checkFunctionReturnType( { node, returns }, options, diff --git a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts index 1bd477f206ce..c22a909b0bbb 100644 --- a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts @@ -821,6 +821,64 @@ export const a: Foo = { f: (x: boolean) => x, }; `, + { + code: ` +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + return a; +} + `, + options: [ + { + allowImplicitReturnTypeForOverloadImplementations: true, + }, + ], + }, + { + code: ` +export default function test(a: string): string; +export default function test(a: number): number; +export default function test(a: unknown) { + return a; +} + `, + options: [ + { + allowImplicitReturnTypeForOverloadImplementations: true, + }, + ], + }, + { + code: ` +export default function (a: string): string; +export default function (a: number): number; +export default function (a: unknown) { + return a; +} + `, + options: [ + { + allowImplicitReturnTypeForOverloadImplementations: true, + }, + ], + }, + { + code: ` +export class Test { + test(a: string): string; + test(a: number): number; + test(a: unknown) { + return a; + } +} + `, + options: [ + { + allowImplicitReturnTypeForOverloadImplementations: true, + }, + ], + }, ], invalid: [ { From c1dd407dd3bb5893edd6db8cdbfd370e1c5e010b Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Tue, 25 Feb 2025 23:35:25 +0200 Subject: [PATCH 2/6] add invalid tests --- .../explicit-module-boundary-types.test.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts index c22a909b0bbb..f5f57f7a2bbe 100644 --- a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts @@ -2135,5 +2135,75 @@ export const foo = { }, ], }, + { + code: ` +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + return a; +} + `, + errors: [ + { + column: 8, + endColumn: 21, + line: 4, + messageId: 'missingReturnType', + }, + ], + }, + { + code: ` +export default function test(a: string): string; +export default function test(a: number): number; +export default function test(a: unknown) { + return a; +} + `, + errors: [ + { + column: 16, + endColumn: 29, + line: 4, + messageId: 'missingReturnType', + }, + ], + }, + { + code: ` +export default function (a: string): string; +export default function (a: number): number; +export default function (a: unknown) { + return a; +} + `, + errors: [ + { + column: 16, + endColumn: 25, + line: 4, + messageId: 'missingReturnType', + }, + ], + }, + { + code: ` +export class Test { + test(a: string): string; + test(a: number): number; + test(a: unknown) { + return a; + } +} + `, + errors: [ + { + column: 3, + endColumn: 7, + line: 5, + messageId: 'missingReturnType', + }, + ], + }, ], }); From 871232a397b6867d0ac81699e67826eccc03db1c Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Wed, 26 Feb 2025 00:01:19 +0200 Subject: [PATCH 3/6] update docs --- .../rules/explicit-module-boundary-types.mdx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx index 339150327d99..85de9f23556e 100644 --- a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx +++ b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx @@ -260,6 +260,37 @@ export const foo: FooType = bar => {}; +### `allowImplicitReturnTypeForOverloadImplementations` + +{/* insert option description */} + +Examples of code for this rule with `{ allowImplicitReturnTypeForOverloadImplementations: false }`: + + + + +```ts option='{ "allowImplicitReturnTypeForOverloadImplementations": false }' +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + return a; +} +``` + + + + +```ts option='{ "allowImplicitReturnTypeForOverloadImplementations": true }' +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + return a; +} +``` + + + + ## When Not To Use It If your project is not used by downstream consumers that are sensitive to API types, you can disable this rule. From 42dd5fa87a7506ed063bd9ba78abb5fd151535a2 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Wed, 26 Feb 2025 00:08:27 +0200 Subject: [PATCH 4/6] change option name and description --- .../docs/rules/explicit-module-boundary-types.mdx | 8 ++++---- .../src/rules/explicit-module-boundary-types.ts | 12 ++++++------ .../rules/explicit-module-boundary-types.test.ts | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx index 85de9f23556e..d7f60dd346da 100644 --- a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx +++ b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx @@ -260,16 +260,16 @@ export const foo: FooType = bar => {}; -### `allowImplicitReturnTypeForOverloadImplementations` +### `allowOverloadFunctions` {/* insert option description */} -Examples of code for this rule with `{ allowImplicitReturnTypeForOverloadImplementations: false }`: +Examples of code for this rule with `{ allowOverloadFunctions: false }`: -```ts option='{ "allowImplicitReturnTypeForOverloadImplementations": false }' +```ts option='{ "allowOverloadFunctions": false }' export function test(a: string): string; export function test(a: number): number; export function test(a: unknown) { @@ -280,7 +280,7 @@ export function test(a: unknown) { -```ts option='{ "allowImplicitReturnTypeForOverloadImplementations": true }' +```ts option='{ "allowOverloadFunctions": true }' export function test(a: string): string; export function test(a: number): number; export function test(a: unknown) { diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index 8b832713e49f..8ec466524988 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -30,7 +30,7 @@ export type Options = [ allowedNames?: string[]; allowHigherOrderFunctions?: boolean; allowTypedFunctionExpressions?: boolean; - allowImplicitReturnTypeForOverloadImplementations?: boolean; + allowOverloadFunctions?: boolean; }, ]; export type MessageIds = @@ -88,10 +88,10 @@ export default createRule({ 'You must still type the parameters of the function.', ].join('\n'), }, - allowImplicitReturnTypeForOverloadImplementations: { + allowOverloadFunctions: { type: 'boolean', description: - 'Whether to ignore missing return type annotations on functions with overload signatures.', + 'Whether to ignore return type annotations on functions with overload signatures.', }, allowTypedFunctionExpressions: { type: 'boolean', @@ -108,7 +108,7 @@ export default createRule({ allowDirectConstAssertionInArrowFunctions: true, allowedNames: [], allowHigherOrderFunctions: true, - allowImplicitReturnTypeForOverloadImplementations: false, + allowOverloadFunctions: false, allowTypedFunctionExpressions: true, }, ], @@ -469,7 +469,7 @@ export default createRule({ } if ( - options.allowImplicitReturnTypeForOverloadImplementations && + options.allowOverloadFunctions && node.parent.type === AST_NODE_TYPES.MethodDefinition && hasOverloadSignatures(node.parent, context) ) { @@ -506,7 +506,7 @@ export default createRule({ } if ( - options.allowImplicitReturnTypeForOverloadImplementations && + options.allowOverloadFunctions && hasOverloadSignatures(node, context) ) { return; diff --git a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts index f5f57f7a2bbe..1897957aa5e3 100644 --- a/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-module-boundary-types.test.ts @@ -831,7 +831,7 @@ export function test(a: unknown) { `, options: [ { - allowImplicitReturnTypeForOverloadImplementations: true, + allowOverloadFunctions: true, }, ], }, @@ -845,7 +845,7 @@ export default function test(a: unknown) { `, options: [ { - allowImplicitReturnTypeForOverloadImplementations: true, + allowOverloadFunctions: true, }, ], }, @@ -859,7 +859,7 @@ export default function (a: unknown) { `, options: [ { - allowImplicitReturnTypeForOverloadImplementations: true, + allowOverloadFunctions: true, }, ], }, @@ -875,7 +875,7 @@ export class Test { `, options: [ { - allowImplicitReturnTypeForOverloadImplementations: true, + allowOverloadFunctions: true, }, ], }, From 9d01f4ed880b6732f03c7056ff38b1512f8950b8 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Wed, 26 Feb 2025 00:10:39 +0200 Subject: [PATCH 5/6] update snapshots --- .../explicit-module-boundary-types.shot | 25 +++++++++++++++++++ .../explicit-module-boundary-types.shot | 6 +++++ 2 files changed, 31 insertions(+) diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot index 8fcda4fd876a..47b4ca6e2a35 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot @@ -192,3 +192,28 @@ type FooType = (bar: string) => void; export const foo: FooType = bar => {}; " `; + +exports[`Validating rule docs explicit-module-boundary-types.mdx code examples ESLint output 11`] = ` +"Incorrect +Options: { "allowOverloadFunctions": false } + +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + ~~~~~~~~~~~~~ Missing return type on function. + return a; +} +" +`; + +exports[`Validating rule docs explicit-module-boundary-types.mdx code examples ESLint output 12`] = ` +"Correct +Options: { "allowOverloadFunctions": true } + +export function test(a: string): string; +export function test(a: number): number; +export function test(a: unknown) { + return a; +} +" +`; diff --git a/packages/eslint-plugin/tests/schema-snapshots/explicit-module-boundary-types.shot b/packages/eslint-plugin/tests/schema-snapshots/explicit-module-boundary-types.shot index aa3494b2c238..ca7169354bdf 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/explicit-module-boundary-types.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/explicit-module-boundary-types.shot @@ -27,6 +27,10 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "description": "Whether to ignore return type annotations on functions immediately returning another function expression.\\nYou must still type the parameters of the function.", "type": "boolean" }, + "allowOverloadFunctions": { + "description": "Whether to ignore return type annotations on functions with overload signatures.", + "type": "boolean" + }, "allowTypedFunctionExpressions": { "description": "Whether to ignore type annotations on the variable of a function expression.", "type": "boolean" @@ -53,6 +57,8 @@ type Options = [ * You must still type the parameters of the function. */ allowHigherOrderFunctions?: boolean; + /** Whether to ignore return type annotations on functions with overload signatures. */ + allowOverloadFunctions?: boolean; /** Whether to ignore type annotations on the variable of a function expression. */ allowTypedFunctionExpressions?: boolean; /** An array of function/method names that will not have their arguments or return values checked. */ From ae67ef732c5fd34ae4c85da4a158f17664dea4f6 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Mon, 3 Mar 2025 01:02:57 +0200 Subject: [PATCH 6/6] update docs --- .../rules/explicit-module-boundary-types.mdx | 21 ++----------------- .../explicit-module-boundary-types.shot | 16 +------------- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx index d7f60dd346da..c4a21e23547c 100644 --- a/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx +++ b/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.mdx @@ -264,23 +264,9 @@ export const foo: FooType = bar => {}; {/* insert option description */} -Examples of code for this rule with `{ allowOverloadFunctions: false }`: +Examples of correct code when `allowOverloadFunctions` is set to `true`: - - - -```ts option='{ "allowOverloadFunctions": false }' -export function test(a: string): string; -export function test(a: number): number; -export function test(a: unknown) { - return a; -} -``` - - - - -```ts option='{ "allowOverloadFunctions": true }' +```ts option='{ "allowOverloadFunctions": true }' showPlaygroundButton export function test(a: string): string; export function test(a: number): number; export function test(a: unknown) { @@ -288,9 +274,6 @@ export function test(a: unknown) { } ``` - - - ## When Not To Use It If your project is not used by downstream consumers that are sensitive to API types, you can disable this rule. diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot index 47b4ca6e2a35..7aba83e40296 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-module-boundary-types.shot @@ -194,21 +194,7 @@ export const foo: FooType = bar => {}; `; exports[`Validating rule docs explicit-module-boundary-types.mdx code examples ESLint output 11`] = ` -"Incorrect -Options: { "allowOverloadFunctions": false } - -export function test(a: string): string; -export function test(a: number): number; -export function test(a: unknown) { - ~~~~~~~~~~~~~ Missing return type on function. - return a; -} -" -`; - -exports[`Validating rule docs explicit-module-boundary-types.mdx code examples ESLint output 12`] = ` -"Correct -Options: { "allowOverloadFunctions": true } +"Options: { "allowOverloadFunctions": true } export function test(a: string): string; export function test(a: number): number;