diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts index 45f7fdbd711..40c504cd677 100644 --- a/packages/eslint-plugin/src/rules/method-signature-style.ts +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -97,6 +97,21 @@ export default util.createRule({ return ''; } + function isNodeParentModuleDeclaration(node: TSESTree.Node): boolean { + if (!node.parent) { + return false; + } + + if (node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) { + return true; + } + + if (node.parent.type === AST_NODE_TYPES.Program) { + return false; + } + return isNodeParentModuleDeclaration(node.parent); + } + return { TSMethodSignature(methodNode): void { if (mode === 'method') { @@ -112,61 +127,79 @@ export default util.createRule({ getMethodKey(element) === getMethodKey(methodNode), ) : []; + const isParentModule = isNodeParentModuleDeclaration(methodNode); if (duplicatedKeyMethodNodes.length > 0) { + if (isParentModule) { + context.report({ + node: methodNode, + messageId: 'errorMethod', + }); + } else { + context.report({ + node: methodNode, + messageId: 'errorMethod', + *fix(fixer) { + const methodNodes = [ + methodNode, + ...duplicatedKeyMethodNodes, + ].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1)); + const typeString = methodNodes.reduce( + (str, node, idx, nodes) => { + const params = getMethodParams(node); + const returnType = getMethodReturnType(node); + return `${str}(${params} => ${returnType})${ + idx !== nodes.length - 1 ? ' & ' : '' + }`; + }, + '', + ); + const key = getMethodKey(methodNode); + const delimiter = getDelimiter(methodNode); + yield fixer.replaceText( + methodNode, + `${key}: ${typeString}${delimiter}`, + ); + for (const node of duplicatedKeyMethodNodes) { + const lastToken = sourceCode.getLastToken(node); + if (lastToken) { + const nextToken = sourceCode.getTokenAfter(lastToken); + if (nextToken) { + yield fixer.remove(node); + yield fixer.replaceTextRange( + [lastToken.range[1], nextToken.range[0]], + '', + ); + } + } + } + }, + }); + } + return; + } + + if (isParentModule) { context.report({ node: methodNode, messageId: 'errorMethod', - *fix(fixer) { - const methodNodes = [ - methodNode, - ...duplicatedKeyMethodNodes, - ].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1)); - const typeString = methodNodes.reduce((str, node, idx, nodes) => { - const params = getMethodParams(node); - const returnType = getMethodReturnType(node); - return `${str}(${params} => ${returnType})${ - idx !== nodes.length - 1 ? ' & ' : '' - }`; - }, ''); + }); + } else { + context.report({ + node: methodNode, + messageId: 'errorMethod', + fix: fixer => { const key = getMethodKey(methodNode); + const params = getMethodParams(methodNode); + const returnType = getMethodReturnType(methodNode); const delimiter = getDelimiter(methodNode); - yield fixer.replaceText( + return fixer.replaceText( methodNode, - `${key}: ${typeString}${delimiter}`, + `${key}: ${params} => ${returnType}${delimiter}`, ); - for (const node of duplicatedKeyMethodNodes) { - const lastToken = sourceCode.getLastToken(node); - if (lastToken) { - const nextToken = sourceCode.getTokenAfter(lastToken); - if (nextToken) { - yield fixer.remove(node); - yield fixer.replaceTextRange( - [lastToken.range[1], nextToken.range[0]], - '', - ); - } - } - } }, }); - return; } - - context.report({ - node: methodNode, - messageId: 'errorMethod', - fix: fixer => { - const key = getMethodKey(methodNode); - const params = getMethodParams(methodNode); - const returnType = getMethodReturnType(methodNode); - const delimiter = getDelimiter(methodNode); - return fixer.replaceText( - methodNode, - `${key}: ${params} => ${returnType}${delimiter}`, - ); - }, - }); }, TSPropertySignature(propertyNode): void { const typeNode = propertyNode.typeAnnotation?.typeAnnotation; diff --git a/packages/eslint-plugin/tests/rules/method-signature-style.test.ts b/packages/eslint-plugin/tests/rules/method-signature-style.test.ts index 3f125b33cdf..72c55e16c4a 100644 --- a/packages/eslint-plugin/tests/rules/method-signature-style.test.ts +++ b/packages/eslint-plugin/tests/rules/method-signature-style.test.ts @@ -348,5 +348,28 @@ interface Foo { }, ], }, + { + code: noFormat` + declare global { + namespace jest { + interface Matchers { + // Add overloads specific to the DOM + toHaveProp>(name: K, value?: DomPropsOf[K]): R; + toHaveProps(props: Partial>): R; + } + } + } + `, + errors: [ + { + messageId: 'errorMethod', + line: 6, + }, + { + messageId: 'errorMethod', + line: 7, + }, + ], + }, ], });