eslint: eqeqeq rule allow-undefined

What rule do you want to change?

Require === and !== (eqeqeq) https://eslint.org/docs/rules/eqeqeq#allow-null

Does this change cause the rule to produce more or fewer warnings?

In ECMA262:

null value is primitive value that represents the intentional absence of any object value.

undefined value is primitive value used when a variable has not been assigned a value.

In TypeScript team coding guidelines:

Use undefined. Do not use null.

https://github.com/microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined

So i think comparing with the undefined literal should also can be allowed.

How will the change be implemented? (New option, new default behavior, etc.)? Please support allow-undefined.

Please provide some example code that this change will affect:

foo == null
foo == undefined

What does the rule currently do for this code?

foo == null // correct
foo == undefined // incorrect

What will the rule do after it’s changed?

foo == null // correct
foo == undefined // correct

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

It’s my pleasure

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 26 (14 by maintainers)

Most upvoted comments

I don’t think this change should be made in core for a few reasons:

  1. Since this is purely stylistic, it falls under our new policy.

  2. If you’re never using null, why not just use a === undefined everywhere? It would be safer and more explicit. The way I read this guideline is that you should never use null to represent a null value for APIs you control. That doesn’t mean you wouldn’t have to use a === null in your code, since there’s a good chance you’ll be interacting with someone else’s code (even if it’s just the Node builtin or DOM APIs) that may return null.

Also note that the undefined literal can be redefined, everywhere but the global scope. == null is the only safe usage of ==.

In the ECMA262 specification, [[Writable]] of undefined is false. So i don’t think is problem to use undefined in 2020.

The value of undefined is undefined (see 6.1.1). This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

And most people use feature like ES Module and Class, they are always in strict mode. In strict mode will throw TypeError when undefined = anything.

I don’t agree - null isn’t buggy.

In the following url, Brendan Eich say in 2011/01/14 20:18:

https://web.archive.org/web/20160331031419/http://wiki.ecmascript.org:80/doku.php?id=harmony:typeof_null

I would very much prefer to fix typeof. We talked about this before, and decided that there is code out there that depends on typeof ‘s bad behavior. Are we now saying that the migration tax is acceptable?

Obviously, this is a bug that the author agreed.

@kaicataldo I never said i never using null, and If you’re never using undefined, why not just use a === null everywhere, why not ban "null": "always" | "never" | "ignore" option.

@ljharb “it avalible to use undefined like foo == undefined” is not “i only use undefined”,and it’s very inaccurate to misrepresent as if it is. That a few vocal industry personalities have said something is “utterly broken” does not mean that the wider community and ecosystem agree. Use of undefined is in no way contrary to JS.

I agree with @SyMind, == undefined should be a permitted option, and indeed a recommended option. I don’t agree with @kaicataldo for the following reasons:

  1. If you don’t want == undefined, just leave the option off — if you want to continue to use null against industry guidance it is up to you — or simply don’t use a linter.
  2. Douglas Crockford advises to never use null in JS, in his words, “it is utterly broken” (due to the typeof “object” bug). By using == undefined to include testing for null, in the very few circumstances that null is returned, we can simply forget about null. See — Douglas Crockford - JS the Better Parts @ 30 minutes
  3. Undefined cannot be removed from code because following TC39 committee decisions, it was selected as the preferred base value for JS, only undefined triggers ES6 default parameters and defaults for object deconstruction. Null was essentially semi-deprecated.
  4. This is not purely stylistic for the reasons above — there is a move to quietly deprecate null by the steering committee of JS and the only way to facilitate that guidance and recommendation is to include == undefined. Plus this is already a rule, but a broken one as it makes absolutely no sense to allow == null as an option and not == undefined — illogical rules, even if stylistic, result in bugs. Thus even if this was stylistic, it is a correction of one that was already included.
  5. There is growing community support for the removal of null from code — see — Intent to stop using null in my JS code and Why I banned null from my JS code
  6. Programmers should never be redefining undefined, it is a long standing rule of very bad programming. Attempting to prevent a minuscule number of reckless programmers from doing something they should not be doing is a weak argument. Besides, if one did redefine undefined most code formatters, e.g. VS code, will indicate a change in color of undefined, thus you would have to be both reckless and unobservant. (If one wanted to, one could overwrite almost every prototype method in JS, but we don’t stop overriding prototypes in EsLint.)
  7. The “if you are never using null” argument above is incorrect. The only way to never use null is to allow == undefined because many external API calls return null, as does string.match() and several other edge cases. By not allowing == undefined it forces the continued use of null throughout code, which is confusing, confusion means lack of clarity, lack of clarity is the biggest cause of bugs. Thus there would be more bugs not fewer. In fact, this kind of thinking leads to the increased use of loose equality throughout as controversially espoused by Kyle Simpson.
  8. Tony Hoare termed “null” the billion dollar mistake for a reason — Null Billion Dollar Mistake
  9. In JS null will coerce to zero, (for no reason other than C permitted null pointers in mathematics equations). Thus null is unsafe for any form of numerical comparison using greater or less than. Undefined will never coerce in these situations and is void(0), a true base value. Thus again, removing null from code should be recommended and is only possible with == undefined as an option.
  10. From the new policy — “Stylistic rules are those related to spacing, conventions, and generally anything that does not highlight an error or a better way to do something.” Since use of null in JS causes errors and is recommended to be deprecated, with wide range of support from industry standard, leading software engineers, TC39 members, textbooks, and the community, this is not simply a stylistic rule, it is a better way to do something subsequent to ES6 adoption.

Also note that the undefined literal can be redefined, everywhere but the global scope. == null is the only safe usage of ==.

As stated many times @ljharb, there is communication from Bredan Eich himself that TC39 rejected null in ES6. I hope you will take the advice of those who actually wrote the language and were there when these decision were made.

Clearly null cannot be deprecated because too many programs now rely on this buggy bit of code, but that has been discussed and an expressed desire at the highest levels of Javascript architects.

Incidentally, even the MDN reference makes use of the undefined literal in numerous examples, it is well accepted and good practice, but again you make extreme statements without supporting proof.

I would still like to know, how does using == null to test for an unintentional absence of a non-object make any sense? If == undefined is deprecated please provide proof. Or is there no proof?

Thanks for the discussion, everyone. There isn’t enough support on the team to implement this change, so we are closing this issue. As a reminder, you do have several options for getting this functionality including the use of the no-restricted-syntax rule or creating your own (either with or without eslint-rule-composer.

There are only two logical approaches here.

  1. EsLint should scrap the allow null rule and neither == null nor == undefined should be permitted.
  2. Both should be included, and if there was any real concern (which I would argue is nonsense) about developers redefining undefined, a separate linting rule warning against redefinition of undefined should be included. Only == undefined has the correct ECMA262 meaning to included both a test objects and non-objects when testing for emptiness, to include == null as the only exception is incorrect in terms of ECMA262 spec, it implies a test of absence of objects and will make code unclear.

Indeed, given the serious warning from MDN, and the serious problems that would be caused by redefining undefined, that should be a rule in EsLint regardless! If a developer redefined undefined, would that make any difference to == undefined being a less robust code? Of course not, the two are separate issues! If a developer redefined undefined they have more to worry about that a linting option, their code would be impossible to debug regardless of EsLint!

@ljharb When the creator of Javascript, Brendan Eich, writes that there is reason to believe typeof null is a bug, it is not a misrepresentation to state that there is wide support for concern over the use of null. Null was specifically excluded from ES6 defaults by the TC39 committee despite robust attempts to have it included - this is fact.

Regardless, I think we are digressing from the point.

As @SyMind correctly stated, ECMA262 states that null is only to be used as the absence of an object - undefined is the absence of any value (including an object). Thus, null in ECMA262 script is a specific instance of undefined, a specific instance that is widely accepted to be buggy. That APIs return null is not a “recommendation” to use null, it is merely ECMA262 specification that it far too this late to change. The argument that it is a recommendation is akin to stating that gas stations selling fuel is a recommendation that we should use gas rather than electric cars - it’s a straw man argument. Only humans can make recommendations, not browser APIs. The only internal JS method that returns null is string.match(), again, we can’t change that, but JS programmers can follow advice from highly experienced programmers to never use null.

Only == undefined has the correct ECMA262 script meaning to included both objects and non-objects when testing for emptiness.

The facts are as follows:

  1. Null is one of the most widely misused values in JS - just look at Stackoverflow - there are numerous non-ESMA262 compliant statements. Even the 2011 edition of Javascript - The Definitive Guide, advised programmers to set Strings, Numbers and Booleans to null instead of undefined if an empty value was required. This is corrected in the 2021 edition to be released.
  2. Why was allow null included as a linting option? To make it easier to test for both undefined and null because as you correctly state, null and undefined are both returned - null only in the case of Objects.
  3. Does it make any sense for the preferred base value, which you accept is undefined to be excluded from the the linting option == undefined? Of course not. This would result in Object properties being set as one thing undefined yet tested for by the a less common value == null, a value that has a specific meaning to objects only, thus causing complete lack of clarity. Only == undefined has the correct ECMA262 script meaning to included both objects and non-objects when testing for emptiness.
  4. MDN warns strongly against redefining undefined.
  5. Does allow null == null without == undefined cause more or less confusion and clarity - the most serious threat to robust code - of course it does, especially given points 1 and 3 above.
  6. Given that there is a very strong warning from MDN not to redefine undefined, is it logical to cause more lack of clarity by making an illogical rule to exclude == undefined thus still allowing users to redefine undefined, or would it be more logical to add a linting rule to warn about the redefinition of undefined as well as a == undefined option.
  7. It is impossible to exclude undefined from JS code because it is set as default, further it is required for ES6 features. However, as numerous, dozens of very experience developers (not very few - I gave three links alone) have very articulately stated - it is actually entirely possible to completely forget that null exists in JS because one can test for it by == undefined, further, null is only returned by a handful of methods, and many API calls.
  8. It is well known, and stated by the one of the fathers of modern computer science, Tony Hoare, that null is the source for more bugs than almost anything else. In JS, this is made worse by the typeof === 'object' bug. Thus avoidance, if possible, should be an entirely recommended goal. Notwithstanding, this may not be the aim of a allow == undefined rule. Simply the rule should be included because of point 1 alone or point 3 alone!

If you do anything on the web, you deal with many APIs, some of which return undefined and some which return null, including in JS itself (''.match(/./), eg). It’s impossible to only ever use one of them - and in the world of modern web dev, most of your code is from dependencies, which you can’t/shouldn’t lint at all, and any of these might return whichever nullish value you hate the most. The purpose of this rule is to prevent all usages of ==/!=, and the choice to make an exception for == null was, i assume, because that was both the common idiom, and also more robust than == undefined.

@lemonbob there’s a few inaccuracies in your comment; TC39 never “selected” a preferred base value for JS, undefined has always been the preferred base value since the language’s inception. null is in no way deprecated by TC39 (which I am a member of). What programmers “should do” isn’t the point; because they can redefine it, robust code needs to be concerned with it. As for coercion, if you’re arguing what programmers should do, then one thing they shouldn’t do is implicitly coerce anything 😃

== undefined should absolutely not be permitted by this rule, and imo a clean codebase would only ever use == null (or != null), or ===.

It seems like there’s a misunderstanding about what this rule is intended to enforce. eqeqeq is not recommending using null or undefined in general. The allow-null option exists so that folks can use the idiomatic shorthand a == null instead of having to write out a === null || a === undefined. The rule doesn’t enforce setting any null values - it’s just for this check.

I can see why folks want to try coalesce around a single nullish value, but this feels like a misapplication of this recommendation. Just because the code doesn’t have the keyword null in it doesn’t mean it isn’t checking if the value is null or not. Since a == null is the convention, is safer, and one can always use a === null || a === undefined if they really don’t want to use a == null, I don’t think adding another option makes much sense. We should be encouraging the safer option.

The good news here is that ESLint is pluggable! If this conversation doesn’t lead to implementing the requested feature in core, we encourage you to create your own custom rule (eslint-rule-composer could be really useful here).

Makes sense to me, but I guess this would be ["error", "always", { "undefined": "ignore" }], rather than allow-undefined.

allow-null is deprecated in favor of "null": "always" | "never" | "ignore".

This is documented at the end of the always section, and in the allow-null section. It feels that the document is missing examples or a whole new section for the "null" option.

The new option for undefined, if accepted, should probably match the existing one for null (though, I’m a bit confused about "never").