Skip to content
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

Rule Proposal: no-unsafe-optional-chaining #13431

Closed
mysticatea opened this issue Jun 21, 2020 · 6 comments
Closed

Rule Proposal: no-unsafe-optional-chaining #13431

mysticatea opened this issue Jun 21, 2020 · 6 comments
Assignees
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules

Comments

@mysticatea
Copy link
Member

mysticatea commented Jun 21, 2020

Please describe what the rule should do:

Disallow the unsafe uses of optional chaining.

What new ECMAScript feature does this rule relate to?

Optional chaining

What category of rule is this? (place an "X" next to just one item)

[x] Warns about a potential error (problem)

Provide 2-3 code examples that this rule will warn about:

//✖ BAD (TypeError)
(obj?.foo).bar
(obj?.foo)()
(obj?.foo)`template`
new (obj?.foo)()
class A extends obj?.foo {}

//✔ GOOD
obj?.foo.bar
obj?.foo()
(obj?.foo ?? val).bar
(obj?.foo ?? val)()
(obj?.foo ?? val)`template`
new (obj?.foo ?? val)()
class A extends obj?.foo ?? B {}

// Unrelated (no-extra-parens rule will remove those parentheses)
(obj?.foo)?.bar
(obj?.foo)?.()
(obj.foo)?.bar
(obj.foo)?.()

[EDIT] With disallowArithmeticOperators: true (defaults to false), additionally disallows operators +, -, *, /, and ** because will generate NaN (or unexpected text). It still allows the operators of comparison, bitwise, logical, and relational.

//✖ BAD
obj?.foo + bar
obj?.foo - bar
obj?.foo * bar
obj?.foo / bar
obj?.foo % bar
obj?.foo ** bar
+obj?.foo
-obj?.foo
var v += obj?.foo
var v -= obj?.foo
var v *= obj?.foo
var v /= obj?.foo
var v %= obj?.foo
var v **= obj?.foo

//✔ GOOD
(obj?.foo ?? val) + bar
var v += obj?.foo ?? val

Why should this rule be included in ESLint (instead of a plugin)?

The parentheses around optional chaining disconnect chaining and change the behavior. This is different behavior from well-known non-optional member accesses. This rule warns potential TypeError risks around the difference. This is about a language feature.

Are you willing to submit a pull request to implement this rule?

Yes.

@mysticatea mysticatea added triage An ESLint team member will look at this issue soon rule Relates to ESLint's core rules feature This change adds a new feature to ESLint labels Jun 21, 2020
@mysticatea mysticatea self-assigned this Jun 21, 2020
@mdjermanovic mdjermanovic added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion and removed triage An ESLint team member will look at this issue soon labels Jun 21, 2020
@mdjermanovic
Copy link
Member

(obj?.foo).bar
(obj?.foo)()
(obj?.foo)`template`
new (obj?.foo)()
class A extends obj?.foo {}

👍 these all look like very possible errors.

obj?.foo + 1     // → NaN

I'm not sure about this, it could be part of a valid code that is going to check for NaN after evaluating some complex expression.

@mysticatea
Copy link
Member Author

@mdjermanovic How about behind an option like disallowBinaryExpression? I'd like to catch that because I guess it will be likely general mistakes.

@mdjermanovic
Copy link
Member

@mdjermanovic How about behind an option like disallowBinaryExpression? I'd like to catch that because I guess it will be likely general mistakes.

Makes sense to me 👍

@mysticatea mysticatea added accepted There is consensus among the team that this change meets the criteria for inclusion and removed evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion labels Jun 23, 2020
@mdjermanovic
Copy link
Member

Should we also report chain expression used as a destructuring source:

var { a } = b?.c; // no-unsafe-optional-chaining error?

if not, prefer-destructuring autofix could hide some bugs that would be otherwise reported:

/* eslint prefer-destructuring: error */

var a = (b?.c).a; // autofix -> var {a} = b?.c;

@mdjermanovic
Copy link
Member

Maybe also array spread and spread in function calls:

[...obj?.foo];

bar(...obj?.foo);

new Bar(...obj?.foo);

@yeonjuan
Copy link
Member

yeonjuan commented Nov 15, 2020

Hi :) @mysticatea Could I work on it?

@mdjermanovic mdjermanovic added this to Planned in Public Roadmap via automation Nov 30, 2020
@btmills btmills closed this as completed in 683ad00 Dec 5, 2020
Public Roadmap automation moved this from Planned to Complete Dec 5, 2020
@eslint-github-bot eslint-github-bot bot locked and limited conversation to collaborators Jun 4, 2021
@eslint-github-bot eslint-github-bot bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Jun 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules
Projects
Public Roadmap
  
Complete
Development

No branches or pull requests

3 participants