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

Enforce use of non-strict equality (==/!=) when comparing to null #6543

Closed
sstur opened this issue Jun 27, 2016 · 23 comments
Closed

Enforce use of non-strict equality (==/!=) when comparing to null #6543

sstur opened this issue Jun 27, 2016 · 23 comments
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 enhancement This change enhances an existing feature of ESLint rule Relates to ESLint's core rules

Comments

@sstur
Copy link
Contributor

sstur commented Jun 27, 2016

Right now I use eqeqeq to enforce strict (===) equality everywhere, except when comparing to null. That is great, but I actually want to go one step further and enforce non-strict (==) equality when comparing any value to null literal.

To put it another way, this will NOT currently throw any lint warning:

let foo;
console.log('is it null', foo == null);
console.log('is it really null', foo === null);

Those two statements are not easy to tell apart during code review. The issue can arise that a coder will use strict equality out of habit yet (in our codebase) they should always use loose equality when comparing to null in order to also catch undefined. Similar code will pass lint and pass tests and then later it might fail in production when undefined sneaks in somehow. I'd like to statically enforce loose equality for null.

Would you be open to a PR?

@eslintbot eslintbot added the triage An ESLint team member will look at this issue soon label Jun 27, 2016
@mysticatea mysticatea added enhancement This change enhances an existing feature of ESLint rule Relates to ESLint's core rules 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 27, 2016
@mysticatea
Copy link
Member

Thank you for this issue.

As far as I know, there is no rule to enforce foo == null in core rules (eqeqeq rule has options to allow foo == null, though).
I think such option or a rule is reasonable.

@eslint/eslint-team what do you think?

@platinumazure
Copy link
Member

Something like an "except-null" option for eqeqeq? I could get on board with that.

@mikesherov
Copy link
Contributor

This would match JSHint eqnull. 👍

@btmills
Copy link
Member

btmills commented Jun 27, 2016

We have "allow-null" that permits but does not require == null, so I think "except-null" makes sense. 👍 I'm willing to champion.

@platinumazure
Copy link
Member

If @mysticatea is on board, I count a champion and two (non-champion) 👍's. (Not counting myself.)

@nzakas
Copy link
Member

nzakas commented Jun 27, 2016

I'll 👍 with the caveat that we need a better option name. We've tried to stay away from using the word "except" because it's unclear what it means. Especially since we have "allow-null", i don't think "except-null" is clear at all.

@sstur we will happily accept a PR once we get the option name figured out.

@nzakas nzakas 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 27, 2016
@platinumazure
Copy link
Member

Some thoughts on option name:

  • require-loose-if-null
  • loose-if-null
  • no-strict-if-null

Let's iterate...

@nzakas
Copy link
Member

nzakas commented Jun 27, 2016

If you go for more than two words, then that should become a property option:

eqeqeq: ["error", {
    someLongOption: true
}];

I'd strongly suggest you avoid "loose" and "strict" as descriptions since those are also modes (loose or nonstrict mode and strict mode) for executing JavaScript.

@platinumazure
Copy link
Member

@nzakas Good points about loose/strict. Regarding an option object key, one issue is that this option cannot be specified in conjunction with "allow-null".

I could see something like this though:

{
    "eqeqeq": ["error", { "eqeqForNull": "allow|always|never" }]
}

Where the default is "never" and the current string option "allow-null" is soft-deprecated and equivalent to "allow" in the new option. Then "always" represents the functionality requested in this issue.

We can continue to iterate on the option name, but is this better?

@btmills
Copy link
Member

btmills commented Jun 28, 2016

Having a named property with "allow" (or "either"?) /always/never" seems like the most explicit. Other options "eqeqNull" or "doubleEqualsNull" (or even "==null", though that would require quotes in yml and js configs).

@mysticatea
Copy link
Member

Thank you, everyone!

There was "never-null" option (means "never use eqeqeq for null") in my head. But object-form option seems better.

By the spec, "smart" option is handling 3 things.

  • Comparing two literal values
  • Evaluating the value of typeof
  • Comparing against null

http://eslint.org/docs/rules/eqeqeq#smart

What about the following object-form options:

{
    "eqeqeq": ["error", {
        "eqeqNull": "never" | "always" | "allow",
        "eqeqTypeof": "never" | "allow",
        "eqeqBetweenLiterals": "never" | "allow"
    }],
    // Or shorthands:
    "eqeqeq": ["error", "always" | "smart" | "allow-null"],
}
  • eqeqNull - the setting for non-strict equality comparison with null
    (such as a == null)
    • "never" (default) - disallows == with null.
    • "always" - enforces == with null. (this is the new behavior)
    • "allow" - allows == with null.
  • eqeqTypeof - the setting for non-strict equality comparison with typeof operator
    (such as typeof a == "number")
    • "never" (default) - disallows == with typeof operator.
    • "allow" - allows == with typeof operator.
  • eqeqBetweenLiterals - the setting for non-strict equality comparison between literals
    (such as 100 == 200)
    • "never" (default) - disallows == between lterals.
    • "allow" - allows == between literals.

Shorthands:

eqeqNull eqeqTypeof eqeqBetweenLiterals
"always" (default) never never never
"smart" allow allow allow
"allow-null" allow never never

@nzakas
Copy link
Member

nzakas commented Jun 28, 2016

I don't think we should use "eqeq" in option names as it's the opposite of the rule. "always" , "never", etc. Should mean "always use ===" and "never use ===".

It might be easiest to deprecate allow-null in favor of an options object:

eqeqeq: [error, always, {
    null: always | never | ignore
}]

Where "ignore" is equivalent to allow-null

@alberto
Copy link
Member

alberto commented Jun 28, 2016

👍 what @nzakas said

@btmills
Copy link
Member

btmills commented Jun 28, 2016

👍 to @nzakas's idea.

Would that just be for null, or would it also have options for typeof and literals as covered by "smart"?

@mysticatea
Copy link
Member

Sounds good. Indeed, opposite options were confused.

@sstur
Copy link
Contributor Author

sstur commented Jun 29, 2016

Thanks @nzakas. That makes perfect sense. I'll work on a PR for that.

@btmills: My issue is purely with null since that has a distinct behavioral difference between == and === that we care about in our codebase. For everything else, I always enforce === regardless of typeof or comparing two primitive literals.

Comparing typeof foo === 'something' is just comparing a string to a string so I don't expect our coders to remember an exception for that. I just explain "Always use strict equality. Except when comparing to null in which case do NOT use strict equality."

@btmills
Copy link
Member

btmills commented Jul 8, 2016

@sstur Just checking in, how are things coming along? Is there anything I can do to help?

@nzakas
Copy link
Member

nzakas commented Jul 13, 2016

@btmills I'd say let's stick with "null" for now. If we get further requests for configuration, we can always add more options. I'm the meantime, we can have this new option only work with "always".

@btmills
Copy link
Member

btmills commented Jul 13, 2016

let's stick with "null" for now

👍 works for me

@mysticatea
Copy link
Member

👍

@nzakas
Copy link
Member

nzakas commented Jul 18, 2016

@sstur are you still working on this?

@sstur
Copy link
Contributor Author

sstur commented Aug 1, 2016

Hi @nzakas and @btmills. Thanks for all the input and sorry for the delay. I am working on this now. I expect to get a PR out early this week.

The plan as I understand it is:

deprecate allow-null in favor of an options object.

eqeqeq: [error, always, {
    null: always | never | ignore
}]

Where "ignore" is equivalent to allow-null

we can have this new option only work with "always"

So to summarize:

  • always -> This will mean what it always has, but it will accept an options object. If the options object is omitted it will be as if you passed {null: "never"}.
  • smart -> This will mean what it always has and not accept any options.
  • allow-null -> This will be deprecated in favor of "always", {null: "ignore"}

I will proceed with that plan. Thanks!

@nzakas
Copy link
Member

nzakas commented Aug 2, 2016

@sstur correct. Thanks!

@sstur sstur changed the title How can I enforce use of non-strict equality (==/!=) when comparing to null? Enforce use of non-strict equality (==/!=) when comparing to null? Aug 5, 2016
@sstur sstur changed the title Enforce use of non-strict equality (==/!=) when comparing to null? Enforce use of non-strict equality (==/!=) when comparing to null Aug 5, 2016
@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Feb 6, 2018
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Feb 6, 2018
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 enhancement This change enhances an existing feature of ESLint rule Relates to ESLint's core rules
Projects
None yet
Development

No branches or pull requests

8 participants