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

Skip to content

Enhancement: [prefer-optional-chain] handle cases where the first logical(s) are unrelated to the proceeding logicals #6332

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
dimaMachina opened this issue Jan 12, 2023 · 4 comments · Fixed by #6397
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@dimaMachina
Copy link

Before You File a Proposal Please Confirm You Have Done The Following...

My proposal is suitable for this project

  • I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).

Link to the rule's documentation

https://typescript-eslint.io/rules/prefer-optional-chain

Description

here is totally safe to refactor as I mention in Pass

Fail

if (!baz || !foo || !foo.bar) {
  
}

Pass

if (!baz || !foo?.bar) {
  
}

Additional Info

https://typescript-eslint.io/play/#ts=4.9.3&sourceType=module&code=JYMwBAFAhARghgLzAH2WKID2mVo9gOngCcBKMAbwCgwwqBfIA&eslintrc=N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6Y6RAM0WloHsalfkwCG8WmQAWo5uki9o-aJHBgAviHVA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3TgwAXxCSgA

@dimaMachina dimaMachina added enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Jan 12, 2023
@bradzacher
Copy link
Member

bradzacher commented Jan 12, 2023

The rule does catch the logical OR case, the issue is that the rule does not catch cases with unrelated logicals at the beginning (playground).

Why? Because it's just a really, really, really hard problem to solve using the AST.
To illustrate this, take your case like this

a || b || b.c

For a human this is really easy to parse and understand, but the AST this produces is this:

{
  type: LogicalExpression,
  operator: '||',
  left: b.c
  right: {
    type: LogicalExpression,
    operator: '||',
    left: a,
    right: b,
  }
}

It's difficult to properly associate the fact that b and b.c are positioned sequentially in the logical in the general case. Parentheses and mixed logicals further complicate this by changing the AST shape due to changing precedence.
Combined with the fact the rule needs to also understand the expressions can be of the form !expr, expr, expr != null, expr !== undefined && expr !== null, ...

It's just a hard problem to solve in the general case!

Happy to accept a PR if anyone wants to solve this in the general case!

@bradzacher bradzacher added accepting prs Go ahead, send a pull request that resolves this issue and removed triage Waiting for team members to take a look labels Jan 12, 2023
@bradzacher bradzacher changed the title Enhancement: prefer-optional-chain should catch logical OR case Enhancement: [prefer-optional-chain] handle cases where the first logical(s) are unrelated to the proceeding logicals Jan 13, 2023
@dimaMachina
Copy link
Author

dimaMachina commented Jan 13, 2023

Hey @bradzacher! Many thanks for the detailed answer!

Why? Because it's just a really, really, really hard problem to solve using the AST.

to be honest is not! and can be solved easily with flatLogicalExpression from eslint-plugin-unicorn

https://github.com/sindresorhus/eslint-plugin-unicorn/blob/df4295b53eb33f7c34b5bd81c1c3ce50192bcb65/rules/no-useless-length-check.js#L35-L41

I remember 1 year ago I wrote a rule prefer-array-includes to do the following and logical expressions are not too scary 😂

Code

1 | foo === null || foo !== 7 || ![8, 9].includes(foo)

Error 1/1

> 1 | foo === null || foo !== 7 || ![8, 9].includes(foo)
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use \`.includes()\`, rather than repeated conditional logical OR \`||\` operators.

Output

1 | foo === null || ![7, 8, 9].includes(foo)

update:

also while checking AST Node you would use LogicalExpression selector but ❗️ it should be :not(LogicalExpression) > LogicalExpression

@bradzacher
Copy link
Member

It's funny cos when I was writing my comment I was thinking that the entire rule could probably be refactored to do exactly that - collect the expressions to remove the AST from the equation.

Theres probably a lot of abstractions that could be built into the rule to improve it and reduce the verbosity of the code.

It's grown a lot over time. Again - happy to accept a PR!

@Josh-Cena
Copy link
Member

Fixed by #6397

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 5, 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 enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
3 participants