Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
In javascript is there really a good reason to never check for boolean true || false such as if(var){}else{}?
I am fairly certain this isn't a duplicate so please bear with me.
I check for boolean true||false using if() as a matter of course in my programming. I've programmed extensively in PHP, some in C# ASP.NET, a bit in Java, a long time ago in C++, & dabled in a few others. Checking for boolean true||false has always been pretty straightforward (as far as I could tell). But in JavaScript I've heard, read, and otherwise been told it's bad. That instead of:
if(var){}else{}
I should instead do:
if(typeof(var) !== 'undefined' || typeof(var) !== null || var !== ''){}else{}
Previous to the six months prior to asking this question (originally on StackOverflow) I was a dabbler in JavaScript. After getting tired of writing & re-writing the long version of the boolean test shown above I finally asked a friend who's done extensive js development for years. My friend supported what I'd read, that I should never test for boolean true or false the way I'm used to. However, after that discussion I have a stronger belief that if(var){}else{} IS actually completely fine in js as it works EXACTLY like I would intuitively expect it to (my jsfiddle testing this)
I've looked around and found various links. The following seemed to be the more relevant:
- Most relevant an article on the good blog javascriptweblog (Angus Croll)
- A kind of similar question on stackoverflow (which to my mind was obvious... checking for a boolean value vs an equality check...)
- Another question very similar to the above on stackoverflow
The thing that convinced me most that my usage is safe and will work fine is the 3rd answer to the first SO question I linked to above given by Incognito. The js spec is very clear about what will & will not evaluate to boolean true||false, and again this is exactly as I would have expected (though have to be reminded that an empty array is an object... but that is specific to JavaScript, while the rest of it is exactly as I would expect).
Can someone please provide a definitive reason to not check for boolean true or false in JavaScrpt, realizing I know the difference between a boolean check and an equality check??
Thanks in advance!
3 answers
As mentioned in another answer, when you have code such as if (someVar)
, you're subject to truthiness. To be more precise, this code will run under the rules of Boolean coercion.
In JavaScript, when you have if (someVar)
, the variable someVar
can be basically "anything" - even a boolean value! If someVar
is not a boolean, it'll be converted according to some rules:
- Booleans are returned as-is.
-
undefined
turns intofalse
. -
null
turns intofalse
. -
0
,-0
, andNaN
turn intofalse
; other numbers turn intotrue
. -
0n
turns intofalse
; otherBigInts
turn intotrue
. - The empty string
""
turns intofalse
; other strings turn intotrue
. - Symbols turn into
true
. - All objects become
true
.
A little test to check this behaviour:
function test(someVar) {
if (someVar) {
console.log(someVar, typeof someVar, 'true');
} else {
console.log(someVar, typeof someVar, 'false');
}
}
for (const v of [ null, undefined, 0, 1, '', 'abc', [], [1, 2], {} ]) {
test(v);
}
Output:
null object false
undefined undefined false
0 number false
1 number true
string false
abc string true
[] object true
[ 1, 2 ] object true
{} object true
Note that any object is type-coerced to true
1 (even an empty array or empty object).
1: Except, of course, null
(which is an object - although it shouldn't - but it's coerced to false
)
Now back to the question: how should I check for a boolean value?
It depends!
If you know that someVar
is a boolean value (either true
or false
, nothing else, and that's guaranteed in another part of the code), then if (someVar)
is the most straighforward way to check it. You don't need anything else to verify if the value is true
or false
.
On the other hand, if you don't know what type someVar
is (or you know, and it can be either a boolean or some other type), and you want to check if the type is boolean, then you could do something like this:
function checkBoolean(someVar) {
if (typeof someVar === 'boolean' && someVar) {
console.log('true');
} else {
console.log('false or not boolean');
}
}
But in this case, if someVar
is false
, it'll enter the else
clause (it's a boolean, but it's not true
). If you want to differentiate between true
, false
and "anything else", then it should be:
function checkBoolean(someVar) {
if (typeof someVar === 'boolean') { // it's a boolean value
// it's either true or false
if (someVar) {
console.log('true');
} else {
console.log('false');
}
} else { // it's not a boolean
console.log('not boolean');
}
}
But if you don't care about the type of someVar
and just want to know if it's "true" or "false" (according to the language's type coercion rules), if (someVar)
is enough.
And of course, if you need a different check (such as "I want empty arrays to be false
"), then just change the clause accordingly (ex: if (Array.isArray(someVar) ? someVar.length > 0 : someVar)
- if it's an array, it can't be empty, otherwise check for truthiness).
Anyway, you must define exactly what you need: check if the type is boolean, or if the type-coerced value is true
/false
, or anything else (ignore null
and undefined
, or empty arrays can't be true
, etc). Then you change the code accordingly.
Regarding the suggested code
IMO, if (typeof(someVar) !== 'undefined' || typeof(someVar) !== null || someVar !== '')
is not a good way to check boolean values. Actually, I believe there's an error in this code. For example, if someVar
is null
, it enters the if
clause:
const someVar = null;
if (typeof(someVar) !== 'undefined' || typeof(someVar) !== null || someVar !== '') {
console.log('ok');
} else {
console.log('not ok');
}
This code prints "ok", because typeof(null)
is not null
.
I believe that typeof(someVar) !== null
is wrong, because it doesn't make sense: typeof anything
will never be null
(according to the language specification, the result of typeof
is always a string).
Actually, it's worse: even if someVar
is undefined
or the empty string, this code will print "ok". That's because typeof(someVar)
is never null
, thus the condition typeof(someVar) !== null
is always true. Therefore, this code is not checking anything.
1 comment thread
if(typeof(var) !== 'undefined' || typeof(var) !== null || var !== ''){}else{}
is a wild thing to write for anything other than a variable that takes either undefined, null, or a string as possible values.
If you expect someVar
to be a boolean, I don't know who would tell you that if (someVar) { ... }
is incorrect.
If you expect someVar
to be a boolean or null or undefined, or you expect it to be some other non-boolean type, then there's an argument for some sort of explicit coverage. People reading if (someVar) { ... }
may expect someVar
to be a boolean, even though JavaScript allows it to be other things. So if you want to express that someVar
is a string, it's arguably better to write if (someVar !== '') { ... }
then if (someVar) { ... }
in order to make that expectation clear, even though they do the same thing. Similarly, if someVar
may be a boolean or null, writing if (someVar === false || someVar === null) { ... }
is clearer than if (!someVar) { ... }
.
These are choices that will affect how some other people will read your code, and not what the machine will do. Programming is an act of communication and not just the puzzle of getting the machine to do the thing you want. Even the code you never share with others might be read by you five years later, and you'll be grateful then for the work you do now to save that you some time.
1 comment thread
r~~'s answer is good, and I absolutely agree that the condition provided in the question is ridiculous and I've never seen anyone suggest it as a generic replacement for if(var)
. But I think the actual advice that is being communicated (perhaps poorly) which is not explicitly called out in r~~'s answer is simply: "Avoid relying on truthiness." Or, more generally, ad-hoc implicit conversions.
This rule means that any boolean test should only be performed on booleans. By this rule, if(var)
is completely fine so long as you know var
is a boolean value. This rule suggests that you should almost never use ==
and should instead prefer ===
(similarly for !=
and !==
). This rule implies that null
and undefined
should be treated as distinct values from true
and false
and should be tested for more explicitly. Something like this is presumably part of what led to the condition you posted, though this rule does not imply that particular condition (and that condition is unnecessarily complicated anyway). This rule definitely rules out broken, old-school patterns like someVar = someParam || SOME_DEFAULT
intended to set someVar
to a default value, SOME_DEFAULT
, if someParam
is not set.
Practically, it's very easy for some value you expect to (only) be a boolean to actually allow non-boolean values, particularly null
and undefined
. To that end, I highly recommend using TypeScript[1] with the strictest settings possible. While TypeScript does allow you to rely on truthiness (though you can use tslint
's strict-boolean-expressions
to warn about this), if you declare a variable as having type boolean
, it will catch the very many ways such variables could fail to be bound to boolean
values. In other words, this is an effective way of actually knowing whether some variable is a boolean value.
My post doesn't justify this rule, but the posts you link and many, many others illustrate the unintuitive behavior and mistakes using truthiness leads to.
-
Or, at least, some other JavaScript type checking approach, though TypeScript is the one I'd recommend and seems to have "won". ↩︎
0 comment threads