Skip to content

Commit bf46f8c

Browse files
timkrautbradzacher
authored andcommitted
feat(no-empty-interface): add allowSingleExtend option (#215)
1 parent 2a4aaaa commit bf46f8c

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

Diff for: packages/eslint-plugin/docs/rules/no-empty-interface.md

+17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,23 @@ interface Bar {
3838
interface Baz extends Foo, Bar {}
3939
```
4040

41+
### Options
42+
43+
This rule accepts a single object option with the following default configuration:
44+
45+
```json
46+
{
47+
"@typescript-eslint/no-empty-interface": [
48+
"error",
49+
{
50+
"allowSingleExtends": false
51+
}
52+
]
53+
}
54+
```
55+
56+
- `allowSingleExtends: true` will silence warnings about extending a single interface without adding additional members
57+
4158
## When Not To Use It
4259

4360
If you don't care about having empty/meaningless interfaces, then you will not need this rule.

Diff for: packages/eslint-plugin/src/rules/no-empty-interface.ts

+35-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
import { TSESTree } from '@typescript-eslint/typescript-estree';
77
import * as util from '../util';
88

9-
export default util.createRule({
9+
type Options = [
10+
{
11+
allowSingleExtends?: boolean;
12+
}
13+
];
14+
type MessageIds = 'noEmpty' | 'noEmptyWithSuper';
15+
16+
export default util.createRule<Options, MessageIds>({
1017
name: 'no-empty-interface',
1118
meta: {
1219
type: 'suggestion',
@@ -21,13 +28,28 @@ export default util.createRule({
2128
noEmptyWithSuper:
2229
'An interface declaring no members is equivalent to its supertype.'
2330
},
24-
schema: []
31+
schema: [
32+
{
33+
type: 'object',
34+
additionalProperties: false,
35+
properties: {
36+
allowSingleExtends: {
37+
type: 'boolean'
38+
}
39+
}
40+
}
41+
]
2542
},
26-
defaultOptions: [],
27-
create(context) {
43+
defaultOptions: [
44+
{
45+
allowSingleExtends: false
46+
}
47+
],
48+
create(context, [{ allowSingleExtends }]) {
2849
return {
2950
TSInterfaceDeclaration(node: TSESTree.TSInterfaceDeclaration) {
3051
if (node.body.body.length !== 0) {
52+
// interface contains members --> Nothing to report
3153
return;
3254
}
3355

@@ -37,10 +59,15 @@ export default util.createRule({
3759
messageId: 'noEmpty'
3860
});
3961
} else if (node.extends.length === 1) {
40-
context.report({
41-
node: node.id,
42-
messageId: 'noEmptyWithSuper'
43-
});
62+
// interface extends exactly 1 interface --> Report depending on rule setting
63+
if (allowSingleExtends) {
64+
return;
65+
} else {
66+
context.report({
67+
node: node.id,
68+
messageId: 'noEmptyWithSuper'
69+
});
70+
}
4471
}
4572
}
4673
};

Diff for: packages/eslint-plugin/tests/rules/no-empty-interface.test.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ interface Bar {
2323
2424
// valid because extending multiple interfaces can be used instead of a union type
2525
interface Baz extends Foo, Bar {}
26-
`
26+
`,
27+
{
28+
code: `
29+
interface Foo {
30+
name: string;
31+
}
32+
33+
interface Bar extends Foo {}
34+
`,
35+
options: [{ allowSingleExtends: true }]
36+
}
2737
],
2838
invalid: [
2939
{
@@ -54,6 +64,7 @@ interface Foo {
5464
5565
interface Bar extends Foo {}
5666
`,
67+
options: [{ allowSingleExtends: false }],
5768
errors: [
5869
{
5970
messageId: 'noEmptyWithSuper',

0 commit comments

Comments
 (0)