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

feat(eslint-plugin): [no-unnecessary-boolean-literal-compare] add option to check nullable booleans #1983

Merged
merged 11 commits into from Jun 20, 2020
Merged

feat(eslint-plugin): [no-unnecessary-boolean-literal-compare] add option to check nullable booleans #1983

merged 11 commits into from Jun 20, 2020

Conversation

zachkirsch
Copy link
Contributor

No description provided.

@typescript-eslint
Copy link
Contributor

Thanks for the PR, @zachkirsch!

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. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitors per day.

@codecov
Copy link

codecov bot commented May 6, 2020

Codecov Report

Merging #1983 into master will increase coverage by 0.03%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master    #1983      +/-   ##
==========================================
+ Coverage   93.40%   93.43%   +0.03%     
==========================================
  Files         174      174              
  Lines        7896     7938      +42     
  Branches     2256     2274      +18     
==========================================
+ Hits         7375     7417      +42     
  Misses        247      247              
  Partials      274      274              
Flag Coverage Δ
#unittest 93.43% <100.00%> (+0.03%) ⬆️
Impacted Files Coverage Δ
packages/eslint-plugin/src/util/types.ts 82.08% <ø> (ø)
...rc/rules/no-unnecessary-boolean-literal-compare.ts 89.61% <100.00%> (+12.46%) ⬆️

@bradzacher bradzacher added awaiting response Issues waiting for a reply from the OP or another party enhancement: plugin rule option New rule option for an existing eslint-plugin rule labels May 6, 2020
@bradzacher
Copy link
Member

thanks for the PR @zachkirsch - could you please provide some context behind this PR?
Why do you want this change?

To me it seems like this option removes a large portion of the usefulness of the rule as the most common case would be a nullable boolean.

@zachkirsch
Copy link
Contributor Author

zachkirsch commented May 7, 2020

Yeah! Two reasons:

Reason 1: Comparing nullable booleans to literal true is unnecessary

Bad Good (and equivalent)
myBooleanOrNullVar === true myBooleanOrNullVar
myBooleanOrNullVar !== true !myBooleanOrNullVar

Reason 2: Comparing nullable booleans to literal false is confusing

I see myOptionalBoolean !== false a lot of the time, usually as optional props (that default to true) in react components. For example:

interface Props {
  // whether to display title (defaults to true)
  displayTitle?: boolean   
}

...

  public render() {
    return (
      <div>
        {this.props.displayTitle !== false && renderTitle()}
        ...

Before ?? existed, myOptionalProp !== false was a sensible way to check an optional prop and default to true if it's undefined. In my opinion, I think that myOptionalProp !== false is a very confusing way to express "use this prop but default to true if it's missing," and IMO it's harder to see bugs that are written that way.

?? is the perfect replacement for this scenario - it's a built-in operator that provides a default if your variable is undefined at runtime. (this.props.displayTitle ?? true) && renderTitle() very clearly means "render the title based on the value of this.props.displayTitle (and default to true if it's not defined)"

To me it seems like this option removes a large portion of the usefulness of the rule as the most common case would be a nullable boolean.

I think this rule is still very useful with this option, as it

  1. catches unnecessary comparisons with boolean variables
    1. e.g. myBoolean !== true --> !myBoolean
  2. catches unnecessary comparisons between nullable boolean variables and true
    1. e.g. myOptionalBoolean !== true --> !myOptionalBoolean
  3. cleans up comparisons between optional booleans and false (described above in this comment)

@bradzacher bradzacher removed the awaiting response Issues waiting for a reply from the OP or another party label May 17, 2020
Copy link
Member

@bradzacher bradzacher left a comment

Choose a reason for hiding this comment

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

mostly lgtm. one comment.
Thanks for your work

};

const defaults = {
allowComparingNullableBooleans: true,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
allowComparingNullableBooleans: true,
allowComparingNullableBooleans: false,

@bradzacher bradzacher added the awaiting response Issues waiting for a reply from the OP or another party label Jun 19, 2020
zachkirsch and others added 2 commits June 19, 2020 13:49
…l-compare.ts

Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
…al-compare.md

Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
@zachkirsch
Copy link
Contributor Author

Sweet! I actually am having some second thoughts haha. I feel like auto-fixing varBooleanOrNull === false to !(varBooleanOrNull ?? true) is kind of weird - the "fixed" version is also a bit hard to parse visually.

Fixing varBooleanOrNull === true to varBooleanOrNull and varBooleanOrNull !== true to !varBooleanOrNull is good IMO. I think fixing varBooleanOrNull !== false to varBooleanOrNull ?? true is also good but I could see it either way.

What are your thoughts? We could also have additional config options that more granularly control which of these four comparisons are checked/fixed by the rule.

@bradzacher
Copy link
Member

bradzacher commented Jun 19, 2020

Hmmm. Sorry, I did a quick eyeball and didn't notice the fix output.
That's my bad.

treat the false and nullish cases the same

  • foo === true => foo
  • foo !== true => !foo

treat the true and nullish cases the same

  • foo === false => foo ?? true
  • foo !== false => !(foo ?? true)

I think that is probably fine.
Personally, I think that the latter two cases might be good to ignore, as IMO they're clearer the other way.

The other option for the last two is to fix to something like foo !== undefined && !foo, but that's pretty verbose, and it's probably better to not fix at all there....

@zachkirsch
Copy link
Contributor Author

Okay, I broke allowComparingNullableBooleans into two options: allowComparingNullableBooleansToTrue and allowComparingNullableBooleansToFalse, so users can decide what they want to allow. If you want, I'm happy to just have the rule ignore comparisons between nullable boolean variables and literal false, but I think it might be confusing if eslint complains about booleanOrNullVar === true but not booleanOrNullVar === false.

I also added some more docs to the rule's readme, including a table of what exactly the fixer does in each case.

@bradzacher bradzacher removed the awaiting response Issues waiting for a reply from the OP or another party label Jun 19, 2020
@zachkirsch
Copy link
Contributor Author

Lemme know if you need anything else from me!

Copy link
Member

@bradzacher bradzacher left a comment

Choose a reason for hiding this comment

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

lgtm - thanks!

@bradzacher bradzacher merged commit c0b3057 into typescript-eslint:master Jun 20, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement: plugin rule option New rule option for an existing eslint-plugin rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants