Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
Loading
from

Conversation

bradzacher
Copy link
Member

PR Checklist

Overview

This PR implements an extension rule for no-unused-private-class-members that introduces support for private members.

@bradzacher bradzacher added the enhancement: new base rule extension New base rule extension required to handle a TS specific case label Mar 3, 2025
@typescript-eslint
Copy link
Contributor

Thanks for the PR, @bradzacher!

typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community.

The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately.

Thanks again!


🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint.

Copy link

netlify bot commented Mar 3, 2025

Deploy Preview for typescript-eslint ready!

Name Link
🔨 Latest commit 34b77b8
🔍 Latest deploy log https://app.netlify.com/sites/typescript-eslint/deploys/67c511602d5b8e00088058ec
😎 Deploy Preview https://deploy-preview-10913--typescript-eslint.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 1 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (🟢 up 8 from production)
SEO: 98 (no change from production)
PWA: 80 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

nx-cloud bot commented Mar 3, 2025

View your CI Pipeline Execution ↗ for commit 34b77b8.

Command Status Duration Result
nx run-many --target=build --exclude website --... ✅ Succeeded 1s View ↗
nx run-many --target=clean ✅ Succeeded 10s View ↗

☁️ Nx Cloud last updated this comment at 2025-03-24 11:52:46 UTC

Copy link

nx-cloud bot commented Mar 3, 2025

View your CI Pipeline Execution ↗ for commit 34b77b8.


☁️ Nx Cloud last updated this comment at 2025-03-03 02:18:54 UTC

Copy link
Member

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conan O'Brien frankly saying 'yep'

@JoshuaKGoldberg JoshuaKGoldberg added the 1 approval >=1 team member has approved this PR; we're now leaving it open for more reviews before we merge label Mar 3, 2025
// mark the first member we encounter as used. If you were to delete the
// member, then any subsequent usage could incorrectly mark the member of
// an encapsulating parent class as used, which is incorrect.
trackedClassMembersUsed.add(memberDefinition.declaredNode);
Copy link
Member

@ronami ronami Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug]: I've noticed some missed reports with functions that have a different this than the class instance (deploy preview playground link):

class Test1 {
  // should be reported but doesn't?
  private bar: number;

  foo = function () {
    return this.bar;
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because the base rule doesn't support that case because this.#bar is a syntax error inside a function expression!!

It's worth noting that TS doesn't actually catch this case either and reports bar as unused because the type of the this in the function expression is any!
If you turn on noImplicitThis then TS will error on that this

We could support this if we wanted to. I'm leaning towards not because TS itself doesn't catch it either.

Copy link
Member

@ronami ronami Mar 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I think the rule should report bar as unused in this case. I've mentioned this since TypeScript reports it as unused but the rule doesn't report it as unused (regardless of the type error).

Comment on lines +219 to +221
PrivateIdentifier(node): void {
processPrivateIdentifier(node);
},
Copy link
Member

@ronami ronami Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug]: I think there's an inconsistency that creates false positives with static private properties (deploy preview playground link):

class Test1 {
  public static foo() {
    return Test1.#bar;
  }

  // correctly not reported
  static #bar = 1;
}

class Test2 {
  public static foo() {
    return Test2.bar;
  }

  // reported but shouldn't?
  private static bar = 1;
}

I've noticed a similar false positive with the following (deploy preview playground link):

class Test1 {
  public foo(a: Test1) {
    return a.#bar;
  }

  // correctly not reported
  #bar = 1;
}

class Test2 {
  public foo(a: Test2) {
    return a.bar;
  }

  // reported but shouldn't?
  private bar = 1;
}

Copy link
Member Author

@bradzacher bradzacher Mar 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For your second example -- this is expected and is the same purposely not covered case as here:
https://github.com/typescript-eslint/typescript-eslint/pull/10913/files#diff-914330b2e3f9d71dfb628800b850412c3c5560900b13cf8a2925ff7af0905e53R50-R66

I made this rule purposely NOT use type info because the cases that type info enable are mostly going to be rarer edge cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first example of static private member access we could handle though with scope analysis.

Copy link
Member

@ronami ronami left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks amazing! Excited to enable this on projects I work on 🚀🚀🚀

(I accidentally posted the review earlier while still adding comments 🙈)

</TabItem>
</Tabs>

## Limitations
Copy link
Member

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?

class Test1 {
  private bar: number;

  foo() {
    const self = this;

    return function () {
      // ❌ NOT detected as a usage
      self.bar;
    }
  }
}

@bradzacher
Copy link
Member Author

FYI I'm going to make @Josh-Cena very happy - I'm going to build a "class scope analyser" so we can do this right rather than just hacking it in.

This does mean that I'm going to rewrite the rule from the ground up -- but it'll be worht it

@kirkwaiblinger
Copy link
Member

kirkwaiblinger commented Mar 19, 2025

FYI I'm going to make @Josh-Cena very happy - I'm going to build a "class scope analyser" so we can do this right rather than just hacking it in.

This does mean that I'm going to rewrite the rule from the ground up -- but it'll be worht it

Do you intend for this to proceed as-is, with this work intended to happen in the future, or should we pause/draft it pending this work?

@bradzacher
Copy link
Member Author

Let's draft it.
We need to at least handle the static property case.
Might have some time soon to pick the work back up.

@kirkwaiblinger kirkwaiblinger added the awaiting response Issues waiting for a reply from the OP or another party label Mar 19, 2025
@kirkwaiblinger kirkwaiblinger marked this pull request as draft March 19, 2025 09:39
@JoshuaKGoldberg JoshuaKGoldberg removed the 1 approval >=1 team member has approved this PR; we're now leaving it open for more reviews before we merge label Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting response Issues waiting for a reply from the OP or another party enhancement: new base rule extension New base rule extension required to handle a TS specific case
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.