Skip to content

Commit

Permalink
fix(eslint-plugin): [method-signature-style] fix overloaded methods t…
Browse files Browse the repository at this point in the history
…o an intersection type (#1966)
  • Loading branch information
sosukesuzuki committed May 4, 2020
1 parent f78f13a commit 7f3fba3
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 0 deletions.
11 changes: 11 additions & 0 deletions packages/eslint-plugin/docs/rules/method-signature-style.md
Expand Up @@ -43,6 +43,11 @@ interface T1 {
type T2 = {
func(arg: boolean): void;
};
interface T3 {
func(arg: number): void;
func(arg: string): void;
func(arg: boolean): void;
}
```

Examples of **correct** code with `property` option.
Expand All @@ -54,6 +59,12 @@ interface T1 {
type T2 = {
func: (arg: boolean) => void;
};
// this is equivalent to the overload
interface T3 {
func: ((arg: number) => void) &
((arg: string) => void) &
((arg: boolean) => void);
}
```

Examples of **incorrect** code with `method` option.
Expand Down
50 changes: 50 additions & 0 deletions packages/eslint-plugin/src/rules/method-signature-style.ts
Expand Up @@ -103,6 +103,56 @@ export default util.createRule<Options, MessageIds>({
return;
}

const duplicatedKeyMethodNodes: TSESTree.TSMethodSignature[] =
methodNode.parent?.type === AST_NODE_TYPES.TSInterfaceBody
? methodNode.parent.body.filter(
(element): element is TSESTree.TSMethodSignature =>
element.type === AST_NODE_TYPES.TSMethodSignature &&
element !== methodNode &&
getMethodKey(element) === getMethodKey(methodNode),
)
: [];

if (duplicatedKeyMethodNodes.length > 0) {
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;
}

context.report({
node: methodNode,
messageId: 'errorMethod',
Expand Down
123 changes: 123 additions & 0 deletions packages/eslint-plugin/tests/rules/method-signature-style.test.ts
Expand Up @@ -226,5 +226,128 @@ interface Foo {
},
],
},
{
code: noFormat`
interface Foo {
foo(): one;
foo(): two;
foo(): three;
}
`,
output: noFormat`
interface Foo {
foo: (() => one) & (() => two) & (() => three);
}
`,
errors: [
{
messageId: 'errorMethod',
line: 3,
},
{
messageId: 'errorMethod',
line: 4,
},
{
messageId: 'errorMethod',
line: 5,
},
],
},
{
code: noFormat`
interface Foo {
foo(bar: string): one;
foo(bar: number, baz: string): two;
foo(): three;
}
`,
output: noFormat`
interface Foo {
foo: ((bar: string) => one) & ((bar: number, baz: string) => two) & (() => three);
}
`,
errors: [
{
messageId: 'errorMethod',
line: 3,
},
{
messageId: 'errorMethod',
line: 4,
},
{
messageId: 'errorMethod',
line: 5,
},
],
},
{
code: noFormat`
interface Foo {
[foo](bar: string): one;
[foo](bar: number, baz: string): two;
[foo](): three;
}
`,
output: noFormat`
interface Foo {
[foo]: ((bar: string) => one) & ((bar: number, baz: string) => two) & (() => three);
}
`,
errors: [
{
messageId: 'errorMethod',
line: 3,
},
{
messageId: 'errorMethod',
line: 4,
},
{
messageId: 'errorMethod',
line: 5,
},
],
},
{
code: noFormat`
interface Foo {
[foo](bar: string): one;
[foo](bar: number, baz: string): two;
[foo](): three;
bar(arg: string): void;
bar(baz: number): Foo;
}
`,
output: noFormat`
interface Foo {
[foo]: ((bar: string) => one) & ((bar: number, baz: string) => two) & (() => three);
bar: ((arg: string) => void) & ((baz: number) => Foo);
}
`,
errors: [
{
messageId: 'errorMethod',
line: 3,
},
{
messageId: 'errorMethod',
line: 4,
},
{
messageId: 'errorMethod',
line: 5,
},
{
messageId: 'errorMethod',
line: 6,
},
{
messageId: 'errorMethod',
line: 7,
},
],
},
],
});

0 comments on commit 7f3fba3

Please sign in to comment.