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

Skip to content

[explicit-member-accessibility] should not be part of recommended #201

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
JamesHenry opened this issue Feb 3, 2019 · 19 comments · Fixed by #729
Closed

[explicit-member-accessibility] should not be part of recommended #201

JamesHenry opened this issue Feb 3, 2019 · 19 comments · Fixed by #729
Labels
has pr there is a PR raised to close this package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin recommended-rules Discussion about recommended rule sets

Comments

@JamesHenry
Copy link
Member

JamesHenry commented Feb 3, 2019

I have just noticed that currently we include

"@typescript-eslint/explicit-member-accessibility": "error",

in recommended.json from eslint-plugin.

I propose that we remove it.

Rationale

TypeScript has always positioned itself as an extension of JavaScript. It is no secret that I think it does a bloody good job at it :)

With it being an extension of JavaScript, there is an expectation that the majority of what you write is JavaScript code, and any syntactic additions provided by TypeScript are there to give you functionality you otherwise do not have.

I strongly believe this does not apply to the public access modifier.

Classes have long been supported in JavaScript, and developers should understand how they work at runtime, regardless of if they use TypeScript or not. As we know, class properties are public in JavaScript.

The private and protected access modifiers do give you functionality you (currently**) otherwise do not have, so adding them to your otherwise valid JavaScript classes is a great capability.

The public access modifier is not only unarguably functionally redundant based on my previous assertions about developers needing to understand JavaScript classes, it is arguably visual clutter when reading the code, and makes it harder to read.

Readability is always subjective, I admit that, but I posit it is harder because having two words (public and private) both beginning with p, both of roughly equal length in front of every single class property makes them less likely to be explicitly distinguishable from one another when scanning code.

An interesting piece of context to this - I often see one of the main reasons people use to justify not using TypeScript is that it is "so different to JavaScript" and "looks like Java". This is absolutely not the case when you approach it in the way I suggest above, and leverage it as an extension to JavaScript. Having a high-profile project like this one recommend a rule like this to developers does not help with that image IMO.

Finally, the rationale for the rule given in the description in the README of the rule is very unclear.

It is conflating the decision of whether or not things should be private to a class, with whether or not public things should use a public access modifier.

Leaving off accessibility modifier and making everything public can make
your interface hard to use by others.
If you make all internal pieces private or protected, your interface will
be easier to use.

These are two completely different things:

Making everything public != Not using the public keyword

I do understand why some people might want to use this rule, and I am not advocating that we should not support it.

I am however, strongly suggesting that it is not appropriate to include it in recommended.

If people wish to provide counter-arguments to what I have said above please do, but please remember keep the focus on the justification as to why it should be in recommended.


**I say currently because of course private properties are coming to JavaScript very soon, and they have completely different syntax to what we are used to with TypeScript today. TypeScript will adapt to this in one way or another, but by leveraging public it means you are doubling down on custom TypeScript syntax in the interim, and so that is also a factor IMO

@JamesHenry JamesHenry added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Feb 3, 2019
@JamesHenry
Copy link
Member Author

cc @typescript-eslint/core-team

@bradzacher bradzacher added question Questions! (i.e. not a bug / enhancment / documentation) and removed triage Waiting for team members to take a look labels Feb 3, 2019
@bradzacher
Copy link
Member

I personally like them, because I'm a sucker for being explicit.

Also coming from someone who has used C#/Java, I like being explicit because without it your code falls into the "default member accessibility" world which has a set of rules depending on where the caller is in relation to the callee.


I hate the proposed JS-standard private syntax.
I've read and understand the reasoning behind it, but I still hate it.
I would hazard a guess that typescript will look to transpiling private into that syntax?


The reason it was added originally was because the majority (if not all) of the community rulesets we looked at had it turned on. None of the ~5-10 community members that looked at the lists in the post objected to that rule, so it stuck.

@JamesHenry
Copy link
Member Author

I like being explicit because without it your code falls into the "default member accessibility" world which has a set of rules depending on where the caller is in relation to the callee.

Are you describing behaviour in those other languages here?

If so, I don’t think it should be a factor in this. Recommended shouldn’t be about making developers from other languages feel at home IMO

@bradzacher
Copy link
Member

Are you describing behaviour in those other languages here?

Yes, this is how Java/C# work - there are tables you can look up to figure out what "default" actually means based on call context.
It doesn't apply to the JS/TS world, sure, but it's the reason I learned to be explicit about my accessibility modifiers, and since then I have maintained that practice because it means your code is clear and easy to understand.

Following from that, I like this rule because it forces people to be consistent in a codebase.
Without the rule, you have a mish-mash of people maybe using private/protected, but on the whole they're going to always use nothing, defaulting to public, or esp if pure JS devs hop into the codebase, you're likely to get public methods with _underscorePrefixed names.

Whilst public provides no additional functionality over nothing, the rule as a whole does because it forces you to take a second to think about the code you're writing.
It forces developers of the codebase to think about how they are setting up the contracts in their code, rather than just defaulting everything to public.

This is especially good when developing code for others to consume, as defaulting everything to public means that it's a breaking change to bring it private.

IMO enforcing a consistent accessibility modifier is a best practice, and should be recommended.

@aboyton
Copy link
Contributor

aboyton commented Feb 3, 2019

We've been debating internally at my workplace if we should be requiring or forbidding the word public. The advantages for us are clear: more "noise" vs being more likely for a developers to make things private (and I definitely like explicit over implicit). Very little of my reasoning for this rule have anything to do with my opinions of Java.

I'm not convinced that it should be recommended (mostly as it's somewhat controversial which way it should be set, although I don't really mind, it's really easy for me to configure it and turning it on makes it obvious to me that it exists) but I think this rule definitely has a lot of value.

@Jessidhia
Copy link
Contributor

Jessidhia commented Feb 4, 2019

This is just an anecdote, but personally public is almost never used because it is the default. In other languages, not making public limits the scope to the module, but neither JS or TS have module-local scope, at least not for properties.

I've only ever written it in constructor properties that are both public and mutable (so I can't use readonly), but it is a very rare use case.

@j-f1
Copy link
Contributor

j-f1 commented Feb 4, 2019

IMO we shouldn’t ban valid JS unless it’s either dangerous in TS or TS has a better alternative.

@JamesHenry
Copy link
Member Author

JamesHenry commented Feb 4, 2019

My interpretation of @bradzacher's position is that the desired outcome is developers are more thoughtful about how they expose implementation details of classes.

This is an admirable goal, I do not disagree with the motivation.

However, the execution of that - forcing all methods to have access modifiers - is a very indirect way to achieve that aim. In my experience of working on the ESLint Team for the last 3 years, lint rules which try to enforce something to indirectly achieve a soft (hard to measure) outcome are what lead to developers declaring their hatred of linters and lead to a lot of frustration for everyone involved.

If they write this particular syntax, their thought process will change/improve is a difficult hypothesis to validate.

It is impossible to say how writing public will affect how people write their code. It is however, easy to quantify what a large impact the burden of adding public to every method on an existing JavaScript codebase is when migrating to TypeScript, and how different it makes otherwise valid JS. There is a clear cost, and an unclear benefit.

It also does not fit with common idioms and examples in the ecosystem, for example in Angular multiple lifecycle methods may be used on a Component's class. You won't see:

public ngOnInit(): void {}
public ngOnChanges(): void {}
public ngOnDestroy(): void {}

But that would be required by this rule. Common idioms can, of course, be based on faulty assumptions etc, but they should not be discounted when evaluating the impact of a deviation imposed by a linting rule.

Let's also not forget that until private properties land in JavaScript, the notion of private is a false friend and should not be overvalued. Your properties are there at runtime, they are exposed. This is JavaScript.

I see the question of whether or not something should be in recommended as:

"Would the ecosystem be clearly better off if everyone wrote their code this way?"

This is a very high bar, but it is definitely worth living up to wherever possible. With its clear cost and unclear benefit, forcing developers to deviate from JavaScript and write public does not meet that standard IMO, and it should be available for people to opt in to only if they want to.

@bradzacher
Copy link
Member

My interpretation of @bradzacher's position is that the desired outcome is developers are more thoughtful about how they expose implementation details of classes

That's it :)
It only really works in conjunction with code reviews though. If nobody is reviewing your code then the onus is entirely on you to not just shut the rule up with public everywhere.


I'm happy to remove it - I'm not overly opinionated for a recommended config (I've always been one to manually define my own rulesets). I tried to base it off of a combination of what the TS team does in their docs + what other ts eslint configs had done.

Technically would be a breaking change though.
Would be good to somehow get more signal from the greater community on this.

@j-f1
Copy link
Contributor

j-f1 commented Feb 4, 2019

Why would it be a breaking change? The only change would be a decrease in the number of reported issues when using the recommended config. If people want those reports back, they can simply enable the rule.

@bradzacher
Copy link
Member

The recommended config is rather opaque from an end-user's perspective.
They mightn't realise if we turn off a rule in the recommended config.

@armano2
Copy link
Collaborator

armano2 commented Feb 4, 2019

what do you think about making 3 configs:

  • base:
    • set parser
    • disable eslint core rules (no-unused-vars etc...)
    • set parserOptions
  • recommended:
    should extends base
    • all rules which prevents errors and unintended behavior
    • if rule is highly opinionated it should not be listed as recommended
  • code-style (not sure about name):
    should extends recommended
    rules that helps keep your code consistent
    • indent
    • explicit-member-accessibility
    • and so on

with that we are giving users a little more granularity and easier way to set up environment

@bradzacher bradzacher added recommended-rules Discussion about recommended rule sets and removed question Questions! (i.e. not a bug / enhancment / documentation) labels Apr 17, 2019
@phaux
Copy link
Contributor

phaux commented Jun 22, 2019

Also note that actual JS syntax for private is gonna be # so the recommended thing should be to stop using TS syntax completely to avoid refactoring in the future

@bradzacher
Copy link
Member

@phaux - not necessarily.. it depends on how typescript handles the transpilation.

They could very well transpile private foo to #foo, meaning you don't have to refactor anything.

@glen-84
Copy link
Contributor

glen-84 commented Jul 20, 2019

They could very well transpile private foo to #foo, meaning you don't have to refactor anything.

Unfortunately not ...

microsoft/TypeScript#9950 (comment)
microsoft/TypeScript#31670 (comment)

@bradzacher
Copy link
Member

That's an interesting read, thank you.
I'd have to read more to understand the differences between the two, but it seems like the typescript team are saying that there's difficulties in that transpilation.

Which makes me think that there is definite use cases for continuing to use private instead of #?
Need to read more!

@j-f1
Copy link
Contributor

j-f1 commented Jul 30, 2019

The difference is that private foo just pretends that you can’t access the foo property when you shouldn’t be allowed to (i.e. if you consume TS code in plain JS, you can access and modify something.foo), whereas #foo actually enforces the guarantees that TS’s type system enforces for private, meaning that JS code can’t access something#foo unless it’s supposed to.

@bradzacher
Copy link
Member

bradzacher commented Jul 30, 2019

But what I'm wondering is - why you ever not use private #foo/#foo instead of just private foo?

@j-f1
Copy link
Contributor

j-f1 commented Jul 30, 2019

No, but it would be a breaking change to transpile private foo to #foo.

kaicataldo pushed a commit to kaicataldo/typescript-eslint that referenced this issue Aug 27, 2019
…eslint#219)

Fixes typescript-eslint#201
Fixes typescript-eslint#96
Fixes eslint/typescript-eslint-parser#577

The [base eslint implementation](https://github.com/eslint/eslint/blob/master/lib/rules/indent.js) purposely ignores nodes it doesn't know about (i.e. our TS nodes).

Because of how the base rule is written, we have to override the implementation entirely.
@typescript-eslint typescript-eslint locked as resolved and limited conversation to collaborators Feb 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has pr there is a PR raised to close this package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin recommended-rules Discussion about recommended rule sets
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants