Skip to content

Commit 071dcd3

Browse files
authored
feat: support TS syntax in no-dupe-class-members (#19558)
* feat: support TS syntax in `no-dupe-class-members` * docs: fix examlpe * chore: remove duplicate note * chore: remove unwanted formatting * chore: remove unwanted formatting
1 parent e849dc0 commit 071dcd3

File tree

3 files changed

+280
-0
lines changed

3 files changed

+280
-0
lines changed

docs/src/rules/no-dupe-class-members.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ class E {
9595

9696
:::
9797

98+
This rule additionally supports TypeScript type syntax. It has support for TypeScript's method overload definitions.
99+
100+
Examples of **correct** TypeScript code for this rule:
101+
102+
::: correct
103+
104+
```ts
105+
/* eslint no-dupe-class-members: "error" */
106+
107+
class A {
108+
foo(value: string): void;
109+
foo(value: number): void;
110+
foo(value: string | number) {} // ✅ This is the actual implementation.
111+
}
112+
```
113+
114+
:::
115+
98116
## When Not To Use It
99117

100118
This rule should not be used in ES3/5 environments.

lib/rules/no-dupe-class-members.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const astUtils = require("./utils/ast-utils");
1515
module.exports = {
1616
meta: {
1717
type: "problem",
18+
dialects: ["javascript", "typescript"],
19+
language: "javascript",
1820

1921
docs: {
2022
description: "Disallow duplicate class members",
@@ -73,6 +75,13 @@ module.exports = {
7375

7476
// Reports the node if its name has been declared already.
7577
"MethodDefinition, PropertyDefinition"(node) {
78+
if (
79+
node.value &&
80+
node.value.type === "TSEmptyBodyFunctionExpression"
81+
) {
82+
return;
83+
}
84+
7685
const name = astUtils.getStaticPropertyName(node);
7786
const kind =
7887
node.type === "MethodDefinition" ? node.kind : "field";

tests/lib/rules/no-dupe-class-members.js

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,256 @@ ruleTester.run("no-dupe-class-members", rule, {
410410
*/
411411
],
412412
});
413+
414+
const ruleTesterTypeScript = new RuleTester({
415+
languageOptions: {
416+
parser: require("@typescript-eslint/parser"),
417+
},
418+
});
419+
420+
ruleTesterTypeScript.run("no-dupe-class-members", rule, {
421+
valid: [
422+
`
423+
class A {
424+
foo() {}
425+
bar() {}
426+
}
427+
`,
428+
`
429+
class A {
430+
static foo() {}
431+
foo() {}
432+
}
433+
`,
434+
`
435+
class A {
436+
get foo() {}
437+
set foo(value) {}
438+
}
439+
`,
440+
`
441+
class A {
442+
static foo() {}
443+
get foo() {}
444+
set foo(value) {}
445+
}
446+
`,
447+
`
448+
class A {
449+
foo() {}
450+
}
451+
class B {
452+
foo() {}
453+
}
454+
`,
455+
`
456+
class A {
457+
[foo]() {}
458+
foo() {}
459+
}
460+
`,
461+
`
462+
class A {
463+
foo() {}
464+
bar() {}
465+
baz() {}
466+
}
467+
`,
468+
`
469+
class A {
470+
*foo() {}
471+
*bar() {}
472+
*baz() {}
473+
}
474+
`,
475+
`
476+
class A {
477+
get foo() {}
478+
get bar() {}
479+
get baz() {}
480+
}
481+
`,
482+
`
483+
class A {
484+
1() {}
485+
2() {}
486+
}
487+
`,
488+
`
489+
class Foo {
490+
foo(a: string): string;
491+
foo(a: number): number;
492+
foo(a: any): any {}
493+
}
494+
`,
495+
],
496+
invalid: [
497+
{
498+
code: `
499+
class A {
500+
foo() {}
501+
foo() {}
502+
}
503+
`,
504+
errors: [
505+
{
506+
column: 5,
507+
data: { name: "foo" },
508+
line: 4,
509+
messageId: "unexpected",
510+
},
511+
],
512+
},
513+
{
514+
code: `
515+
!class A {
516+
foo() {}
517+
foo() {}
518+
};
519+
`,
520+
errors: [
521+
{
522+
column: 4,
523+
data: { name: "foo" },
524+
line: 4,
525+
messageId: "unexpected",
526+
},
527+
],
528+
},
529+
{
530+
code: `
531+
class A {
532+
'foo'() {}
533+
'foo'() {}
534+
}
535+
`,
536+
errors: [
537+
{
538+
column: 4,
539+
data: { name: "foo" },
540+
line: 4,
541+
messageId: "unexpected",
542+
},
543+
],
544+
},
545+
{
546+
code: `
547+
class A {
548+
10() {}
549+
1e1() {}
550+
}
551+
`,
552+
errors: [
553+
{
554+
column: 4,
555+
data: { name: "10" },
556+
line: 4,
557+
messageId: "unexpected",
558+
},
559+
],
560+
},
561+
{
562+
code: `
563+
class A {
564+
foo() {}
565+
foo() {}
566+
foo() {}
567+
}
568+
`,
569+
errors: [
570+
{
571+
column: 4,
572+
data: { name: "foo" },
573+
line: 4,
574+
messageId: "unexpected",
575+
},
576+
{
577+
column: 4,
578+
data: { name: "foo" },
579+
line: 5,
580+
messageId: "unexpected",
581+
},
582+
],
583+
},
584+
{
585+
code: `
586+
class A {
587+
static foo() {}
588+
static foo() {}
589+
}
590+
`,
591+
errors: [
592+
{
593+
column: 4,
594+
data: { name: "foo" },
595+
line: 4,
596+
messageId: "unexpected",
597+
},
598+
],
599+
},
600+
{
601+
code: `
602+
class A {
603+
foo() {}
604+
get foo() {}
605+
}
606+
`,
607+
errors: [
608+
{
609+
column: 4,
610+
data: { name: "foo" },
611+
line: 4,
612+
messageId: "unexpected",
613+
},
614+
],
615+
},
616+
{
617+
code: `
618+
class A {
619+
set foo(value) {}
620+
foo() {}
621+
}
622+
`,
623+
errors: [
624+
{
625+
column: 4,
626+
data: { name: "foo" },
627+
line: 4,
628+
messageId: "unexpected",
629+
},
630+
],
631+
},
632+
{
633+
code: `
634+
class A {
635+
foo;
636+
foo = 42;
637+
}
638+
`,
639+
errors: [
640+
{
641+
column: 4,
642+
data: { name: "foo" },
643+
line: 4,
644+
messageId: "unexpected",
645+
},
646+
],
647+
},
648+
{
649+
code: `
650+
class A {
651+
foo;
652+
foo() {}
653+
}
654+
`,
655+
errors: [
656+
{
657+
column: 4,
658+
data: { name: "foo" },
659+
line: 4,
660+
messageId: "unexpected",
661+
},
662+
],
663+
},
664+
],
665+
});

0 commit comments

Comments
 (0)