Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Bug: [class-literal-property-style] The overridden literal getter does not pass lint and incorrectly auto-fix #5962

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

Closed
4 tasks done
sviat9440 opened this issue Nov 10, 2022 · 4 comments · Fixed by #7054
Closed
4 tasks done
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working good first issue Good for newcomers package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@sviat9440
Copy link
Contributor

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have searched for related issues and found none that matched my issue.
  • I have read the FAQ and my problem is not listed.

Playground Link

https://typescript-eslint.io/play/#ts=4.8.4&sourceType=module&code=MYGwhgzhAECC0G8CwAoa0D6AXAphLAXNPgE4CWAdgOYDcqq6VOW0u+AFAJRGmVWIN00EswCuJCqwAWZCADpseLHTTQAvqg0pUoSDABC0HAA9cFACYx4yVUxZssXHlnLUBq9CKzjJAcge+KuhaWkA&eslintrc=N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6M+AQ2WVsf0TRO8WsWgB7UtCK1kRJOiiCJ0SODABfEBqA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3QAacDUjoAHoizJ46IngCGqACL9YmNXl3Cwo9FIC+IM0A

Repro Code

class A {
  _test: string;

  get test(): string {
    return this._test;
  }
}

class B extends A {
  get test(): string {
    return 'test';
  }
}

ESLint Config

module.exports = {
  "rules": {
    "@typescript-eslint/class-literal-property-style": "error"
  }
}

tsconfig

{
  "compilerOptions": {
    "strictNullChecks": true,
    "experimentalDecorators": true
  }
}

Expected Result

There are no errors because the getter is overridden

Actual Result

Error: Literals should be exposed using readonly fields.

Auto-fix:

class A {
  _test: string;

  get test(): string {
    return this._test;
  }
}

class B extends A {
  readonly test = 'test';
}

Then TypeScript error:
'test' is defined as an accessor in class 'A', but is overridden here in 'B' as an instance property.

Additional Info

No response

Versions

package version
@typescript-eslint/eslint-plugin 5.42.1
@typescript-eslint/parser 5.42.1
TypeScript 4.8.4
ESLint 8.15.0
node web
@sviat9440 sviat9440 added bug Something isn't working package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Nov 10, 2022
@Josh-Cena
Copy link
Member

Related to #5961

I think it should be fixed in two parts:

  1. We should definitely change it to a suggestion fixer because changing between fields and getters changes the semantics of the program (defined on the instance vs. defined on prototype)
  2. Changing from a getter to a field is dangerous: if your child class has a getter that's meant to override the base class's getter, changing the base class's getter to a field makes the child's getter useless.

We need to think more deeply about the semantics of this rule 🤔

Accepting a PR to change it to a suggestion fixer for now.

@Josh-Cena Josh-Cena added accepting prs Go ahead, send a pull request that resolves this issue good first issue Good for newcomers and removed triage Waiting for team members to take a look labels Nov 11, 2022
sviat9440 added a commit to MillerSvt/typescript-eslint that referenced this issue Nov 13, 2022
[prefer-optional-chain] A literal getter with a setter does not pass lint, and incorrectly auto-fix (typescript-eslint#5961)

[prefer-optional-chain] The overridden literal getter does not pass lint and incorrectly auto-fix (typescript-eslint#5962)

BREAKING CHANGE
sviat9440 added a commit to MillerSvt/typescript-eslint that referenced this issue Nov 14, 2022
[prefer-optional-chain] A literal getter with a setter does not pass lint, and incorrectly auto-fix (typescript-eslint#5961)

[prefer-optional-chain] The overridden literal getter does not pass lint and incorrectly auto-fix (typescript-eslint#5962)

BREAKING CHANGE
@bradzacher
Copy link
Member

changing between fields and getters changes the semantics of the program (defined on the instance vs. defined on prototype)

Whilst yes, it's technically a change in behaviour - in the vast majority of code this difference isn't actually a change that would cause any runtime difference.

The only real time the difference is going to come into effect is when you're accessing the member in the superclass's constructor. For all other real usages I can think of right now you're just going to be accessing the instance directly (this.member, foo.member) - so there's no difference if it's a prototype or instance member.

Ultimately the intersection of the "times that that problem's going to occur" and "this rule will fire" is going to be quite small. To be clear - you specifically need to have a getter defined on a class that returns a literal whose parent class accesses that accessor in the constructor.
A very small intersection - I'd hazard a guess that it's probably never happened!

Also worth noting that TS doesn't model the prototype vs instance behaviour (and neither do more sound checkers like flow) because it's just not something that matters to code.


I'm reluctant for us to remove the autofixer from this usecase considering it's such a rare case, but I'm okay as long as it remains a suggestion fixer.

We definitely shouldn't stop reporting on this case given how rare it is.
If the difference between prototype and instance is explicitly required in your codebase - this isn't a rule you should be using, TBH.

@Josh-Cena
Copy link
Member

To be clear, it breaks any time you try to make a "stub getter" for children to override.

class P {
  get a() {
    return "stub";
  }
}

class C extends P {
  get a() {
    console.log("Do something more complicated");
    return "Actual stuff";
  }
}

new C().a; // "Actual stuff"
class P {
  a = "stub";
}

class C extends P {
  get a() {
    console.log("Do something more complicated");
    return "Actual stuff";
  }
}

new C().a; // "stub"

Is this common? —I don't know, maybe it's not, but that's actually an intended use case of accessors (especially with auto-accessors to be introduced with decorators, I expect it to be even more common). Is there a good way to change the code pattern to appease the rule? —Maybe not, except for a disable comment. I was playing with this with @JoshuaKGoldberg and I attempted to make the getter abstract, but it turns out you can't have an abstract getter and a concrete setter, so... ¯_(ツ)_/¯

@bradzacher
Copy link
Member

Is this common? —I don't know, maybe it's not
...
Is there a good way to change the code pattern to appease the rule? —Maybe not, except for a disable comment.

When looking at lint rules basing decisions based on our experience is really the best way for us to make judgements about what rules should exist.
As a group the maintainers have seen millions of lines of code across many dozens of codebases. If we haven't seen a pattern before - then likely it isn't a common pattern that people do!

This evaluation is important because some rules are just going to work for some codebases and some rules aren't. If we make judgements about lint rules based on what some codebases might possibly do and how they might break if the rule's turned on - then a lot of really good rules might not exist!

As a related example - the unbound-method rule mostly relies upon people auto-binding methods by converting them to arrow-function properties which has the same prototype vs instance problem you've mentioned.

but that's actually an intended use case of accessors

Is it? Based on my understanding of the spec - auto-accessors are designed to work well with decorators (hence they are included in the decorators spec)
If you've got some references that suggest that stubbing is an intended usecase I'd love to read so I can understand more!


I personally have never seen someone implement an accessor with the intention that a child class must explicitly override it. It's obviously not THAT uncommon though considering TS has abstract accessors though.
I would probably say that for all cases you'd want an abstract accessor instead of a stubbed getter. I would also say that the usecases of a stubbed getter but an unstubbed setter are really getting into the realm of bad code as you're probably abusing property assignment side-effects at that point.

sviat9440 added a commit to MillerSvt/typescript-eslint that referenced this issue Jan 29, 2023
[prefer-optional-chain] A literal getter with a setter does not pass lint, and incorrectly auto-fix (typescript-eslint#5961)

[prefer-optional-chain] The overridden literal getter does not pass lint and incorrectly auto-fix (typescript-eslint#5962)

BREAKING CHANGE
sviat9440 added a commit to MillerSvt/typescript-eslint that referenced this issue Jan 29, 2023
[prefer-optional-chain] A literal getter with a setter does not pass lint, and incorrectly auto-fix (typescript-eslint#5961)

[prefer-optional-chain] The overridden literal getter does not pass lint and incorrectly auto-fix (typescript-eslint#5962)

BREAKING CHANGE
sviat9440 added a commit to MillerSvt/typescript-eslint that referenced this issue Jan 29, 2023
[prefer-optional-chain] A literal getter with a setter does not pass lint, and incorrectly auto-fix (typescript-eslint#5961)

[prefer-optional-chain] The overridden literal getter does not pass lint and incorrectly auto-fix (typescript-eslint#5962)
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working good first issue Good for newcomers package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
3 participants