-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): [no-unused-private-class-members] new extension rule #10913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
34b77b8
0854007
df85b86
8710810
fe8c300
e72b89a
a43dc70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
--- | ||
description: 'Disallow unused private class members.' | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
> 🛑 This file is source code, not the primary documentation location! 🛑 | ||
> | ||
> See **https://typescript-eslint.io/rules/no-unused-private-class-members** for documentation. | ||
|
||
This rule extends the base [`eslint/no-unused-private-class-members`](https://eslint.org/docs/rules/no-unused-private-class-members) rule. | ||
It adds support for members declared with TypeScript's `private` keyword. | ||
|
||
## Options | ||
|
||
This rule has no options. | ||
|
||
## Examples | ||
|
||
<Tabs> | ||
<TabItem value="❌ Incorrect"> | ||
|
||
```ts | ||
class A { | ||
private foo = 123; | ||
} | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="✅ Correct"> | ||
|
||
```tsx | ||
class A { | ||
private foo = 123; | ||
|
||
constructor() { | ||
console.log(this.foo); | ||
} | ||
} | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
## Limitations | ||
|
||
This rule does not detect the following cases: | ||
|
||
(1) Private members only used using private only without `this`: | ||
|
||
```ts | ||
class Foo { | ||
private prop = 123; | ||
|
||
method(a: Foo) { | ||
// ✅ Detected as a usage | ||
const prop = this.prop; | ||
|
||
// ❌ NOT detected as a usage | ||
const otherProp = a.prop; | ||
} | ||
} | ||
``` | ||
|
||
(2) Usages of the private member outside of the class: | ||
|
||
```ts | ||
class Foo { | ||
private prop = 123; | ||
} | ||
|
||
const instance = new Foo(); | ||
// ❌ NOT detected as a usage | ||
console.log(foo['prop']); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you don't want to be notified about unused private class members, you can safely turn this rule off. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { ESLintUtils } from '@typescript-eslint/utils'; | ||
|
||
import { createRule } from '../util'; | ||
import { analyzeClassMemberUsage } from '../util/class-scope-analyzer/classScopeAnalyzer'; | ||
|
||
type Options = []; | ||
export type MessageIds = 'unusedPrivateClassMember'; | ||
|
||
export default createRule<Options, MessageIds>({ | ||
name: 'no-unused-private-class-members', | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
description: 'Disallow unused private class members', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about covering the following use-case? (deploy preview link) class Test1 {
// should be reported but doesn't?
constructor(private foo: number) {}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a bug and shouldn't be reported (deploy preview playground link): class Test1 {
// reported but shouldn't?
private foo: number | null;
public bar() {
this.foo ??= 1;
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a weird case that isn't currently reported by It is reported by the base |
||
extendsBaseRule: true, | ||
requiresTypeChecking: false, | ||
}, | ||
|
||
messages: { | ||
unusedPrivateClassMember: | ||
"Private class member '{{classMemberName}}' is defined but never used.", | ||
}, | ||
|
||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
return { | ||
'Program:exit'(node) { | ||
const result = analyzeClassMemberUsage( | ||
node, | ||
ESLintUtils.nullThrows( | ||
context.sourceCode.scopeManager, | ||
'Missing required scope manager', | ||
), | ||
); | ||
|
||
for (const classScope of result.values()) { | ||
for (const member of [ | ||
...classScope.members.instance.values(), | ||
...classScope.members.static.values(), | ||
]) { | ||
if ( | ||
(!member.isPrivate() && !member.isHashPrivate()) || | ||
member.isUsed() | ||
) { | ||
continue; | ||
} | ||
|
||
context.report({ | ||
node: member.node.key, | ||
messageId: 'unusedPrivateClassMember', | ||
data: { classMemberName: member.name }, | ||
}); | ||
} | ||
} | ||
}, | ||
}; | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about also mentioning assigning
this
to a variable as a limitaiton?