In JavaScript, it's commonly seen as best practice to use === instead of ==, for obvious and well-known reasons.
In TypeScript, which is one to be preferred? Is there even one which is preferable to the other one?
IMHO, using === in TypeScript doesn't make sense, since comparison already only works on equal types, hence you won't have the (more or less funny) coercion game as in plain JavaScript. If you take aside compatibility to JavaScript for a minute, TypeScript could even get rid of ===, couldn't it?
short version:
== can do unexpected type conversions, in Javascript 1=="1" is true. The === operator avoids this. Comparing different types with === is always false.
The typescript compiler will emit an error message when you compare different types with ==. This removes the unexpected type conversions that can happen with == in Javascript.
This is a case where valid Javascript leads to an error message in the typescript compiler. The idea that all valid Javascript is also valid Typescript is a common misconception. This is simply not true.
longer version:
I think the accepted answer is misleading. Typescript actually does fix == vs === (as far as possible at least).
In Javascript there are two comparison operators:
== : When comparing primitive values, like numbers and strings, this operator will apply a type conversion before doing the comparison. 1 == "1" evaluates to true.
===: This operator does not do type conversions. If the types don't match it will always return false.
Also, both operators will compare reference types based on their references. Two separate objects are never considered equal to each other, even if they store the same values:
let a = {val:1};
let b = {val:1};
c = a;
a==b; // false
a===b; // false
a==c; //true
a===c; //true
So there you have the two common sources of errors in Javascript comparisons:
comparing different types with == can lead to unexpected type conversions.
comparing objects and arrays is based on references not values stored inside.
As the existing answer already says, Typescript is designed as a superset of Javascript. So it doesn't change the behaviour of these comparison operators. If you write == in Typescript, you get type conversions.
So how is this fixed? With the compiler. If you actually do write code that compares incompatible types with == it's a compiler error. Try compiling the following sample:
let str = "1";
let num = 1;
console.log(str == num);
The compiler will tell you:
comparisons.ts:4:13 - error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
4 console.log(str == num);
~~~~~~~~~~
Found 1 error.
It is a common misconception that any valid Javascript is also valid Typescript. This is not true and the code above is an example where the typescript compiler will complain about valid Javascript.
This fixes the first of the two sources of errors: unexpected type conversions. It doesn't deal with the second source of errors: comparisons based on references. As far as I know, when you want to do a comparison based on values stored by the objects, you simply can't use these operators. You'll have to implement your own equals() method.
Also, you may have noticed that the compiler error is wrong. The comparison will not always evaluate to false. I think this is a bug in typescript and have filed an issue.
Imagine you're designing TypeScript from scratch. Essentially, you're trying to optimize for making safer code easier to write (TypeScript design goal 1) with a few caveats which prevent you from doing everything you'd like.
JavaScript compatibility (TypeScript design goal 7)
JavaScript should be valid Typescript with no changes.
CoffeeScript makes no guarantees regarding this, so it can convert all instances of == to === and simply tell users don't rely on =='s behavior. TypeScript cannot redefine == without breaking all JavaScript code that relies on its behavior (despite this having sad implications for 3).
This also implies that TypeScript cannot change the functionality of === to, for example, check the types of both operands at compile time and reject programs comparing variables of different types.
Further, compatibility is not limited to simply JavaScript programs; breaking compatibility also affects JavaScript programmers by breaking their assumptions about the differences between == and ===. See TypeScript non-goal number 7:
Introduce behaviour that is likely to surprise users. Instead have due consideration for patterns adopted by other commonly-used languages.
JavaScript as the target of compilation (TypeScript design goal 4)
All TypeScript must be representable in JavaScript. Further, it should be idiomatic JavaScript where possible.
Really though, the TypeScript compiler could use methods returning booleans for all comparisons, doing away with == and === entirely. This might even be safer for users: define a type-safe equality method on each TypeScript type (rather like C++ operator==, just without overloading).
So there is a workaround (for users comparing classes). unknown or any variables can have their types narrowed before using the type-safe equality method.
Which to prefer
Use === everywhere you would in JavaScript. This has the advantage of avoiding the pitfalls common to ==, and doesn't require you to maintain an additional method. The output of the TypeScript compiler will be close to idiomatic JavaScript. Using == has very much the same pitfalls as JavaScript, particularly when you have any, [], or {} involved. As an exception, using == null to check for null or undefined may save headaches if library code is inconsistent.
A method for reference equality (behavior like === for classes) could be confused with a deep/value recursive equality check. Furthermore, === is widely used in TypeScript, and making your code fall in line with conventions is usually more important than any small bit of type safety.
Your intuition was correct. There's no sense to use === in TypeScript to imitate an equality check. The argument that TS compiles to JS "so you should use what is better in JS" is not valid. Why? Because Typescript ensures that both operands of comparison operator(s) have the same type. When both operands have the same type == and === behave identically. And by "identically" I mean 100% identical not just "alike". So there's no more correct or less correct version when both behave exactly the same way in JavaScript.
I guess other commenters here are just looking for ways to preserve their habit of using === or in other words to rationalize. Unfortunately, pure logic tells otherwise: there's no sense to replace == with ===, unless you're going to modify generated JS code manually which is probably never the case.
I use === exclusively for identity checks (when you compare x to x – the same variables, it's sometimes necessary in library code related to memoization). And my counter of errors related to eqeq operator shows 0.
Example:
const s : string = "s"
const n : number = 1
console.log(s == n)
TS2367: This condition will always return 'false' since the types 'string'
and 'number' have no overlap
My opinion is that one should always use ===.
First line of reasoning: TypeScript does not change == to ===. There're TypeScript translators which just strip types. So using === everywhere leads to more robust code if for some reason you forgot to type check your program or if you (or future maintainer of your code) used type casts to override type safety. Should not happen but many things should not happen.
Second line of reasoning: null == undefined. This is true with TypeScript as well. I think that if one writes if (x == null) it makes code less readable because it implies check for undefined as well and implicit code is less readable than explicit if (x === null || x === undefined). Also subtle bugs might occur if this is not done on purpose.
I don't see any issues when just using === everywhere unconditionally other than aesthetic preferences.
Related
I oftentimes see answers using strict comparison (===) instead of normal comparison (==) on status checking, i.e. here:
if(document.readyState === 'complete') ...
I would understand the reason if it were applied on empty string and the obtained value could be also other falsy value with different meaning. But when applied on non-empty string (like 'complete' in the sample), I believe the result is always the same for '==' and '==='. Is that so?
Some people measured that '===' can be faster, but I haven't seen a real world example where it would make any observable difference, so I don't take this micro-optimalization seriously.
On the other hand, anytime I see this operator, I read it as a warning "mind the type here!". But since document.readyState is always string, it annoys me that the original coder made me to study the code what other types there can appear - only to find out that only string.
To me, it is a strong reason to be polite to those who read my code and never use '===' when the type plays no role in the comparison.
Since '===' appears in similar cases in many SO answers and many expert pages, I would like to know if it is just social bandwagon or if there is any good reason why to use it in status checking.
I would recommend always using '===' instead of '==' when strict equality checking is required, which it is in most cases, for this reason: it declares intent. When I see code with '===', I will read it as 'a must be referentially or primitively equal to b'. When I see '==', I will read it as 'a must be coercibly equal to b'. From that, I will judge what kind of goal the code / original programmer is trying to accomplish and how they are passing data around to get the job done. Essentially, it yields insight into the context of the application, the way data is being passed around, and how this function / method / code block fits into the picture.
With that being said, if I see someone do 'a == b' when they are both strings, I'm not going to get on any high horse and make a fuss about it.
It always depends on what you want to achieve, and what you consider to be equal.
== is not always bad, but it often can lead to false assumptions.
If you have something like this:
class TestA {
toString() {
return 'complete'
}
}
class TestB {
valueOf() {
return 'complete'
}
}
let testA = new TestA()
let testB = new TestB()
console.log(testA == 'complete')
console.log(testB == 'complete')
Then testA == 'complete' might be exactly what you want, but because it does an implicit cast, you might do a false assumption about it being a string when it evaluates to true.
So if you later want to call something like substring on it, or passing it to another function that expects an actual string, then it might fail with an unexpected error.
Using === over == is mostly about maintainability, if you start to refactor code or if you look at older code and you see a == you always need to think about if you really want to have an implicit cast at that point or if it this was an accident. So you need to follow the code flow or check if it was documented.
Using an explicitly and === does not prevent you from doing other mistakes, but it keeps the code consistent.
Java is a Strong Static Casting so does that mean there is no use for "==="
I have looked at tons of documentation and have not seen Identical Comparison Operator.
=== is useful in weak typed languages, such as Javascript, because it verifies that the objects being compared are of the same type and avoids implicit conversions.
=== has absolutely no use in a strongly typed language such as Java because you can't compare variables of different types without writing a specific method for doing this.
For example, if you want to compare an int to a String in Java, you will have to write some special method as such:
boolean compareIntString(int i, String s) {
return (i == parseInt(s));
}
But this is pretty much overkill. (And as you'll notice, as written, this method only accepts an int and a String. It doesn't accept just any two variables. You know before you call it that the datatypes are different.)
The main point is, that while you can do i == s in Javascript, you can't do i == s in Java, so you don't need ===.
I guess, the short answer is that Java's == is Javascript's ===. If you want to emulate Javascript's == and compare two items, ignoring data type, you'll have to write a custom method which accepts generic data types as arguments... and figure out the logic on comparing, at a minimum, all the possible combinations of Java's primitive data types...
No java does not have === operator. Reason is pretty well explained by nhgrif. Here is the list of operators in java and their precedence:
Source: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
Since a few months, my IDE (WebStorm) highlights JavaScript regular equality operators with the following warning:
Comparioson a == b may cause unexpected type coercion.
This inspection reports usages of JavaScript quality operators which may cause unexpected
type coercions. It is considered a good practice to use the type-safe equality operators
=== and !== instead of their regular counterparts == and !=.
I am aware of the different behavours of both operators and I tend to use them because of their different behavour, eg. for lazy type conversions:
if(parseInt(val) == val) // val can be safely converted to int
However, the IDE is adding warnings to all occurences of ==, so the above does not feel right anymore. I'm could convert all these parts into something much less readable:
if(parseInt(val).toString() === val) // be happy webstorm
Is this really the way to go; or should I rather ignore/disable these warnings?
Yes, this has been best practice for almost two decades.
The warning is quite clear (even explaining why it's in place), and you'll find the same advice in your JavaScript books as well as widely across the web.
So, I can't comprehend why you'd consider ignoring or even disabling it.
You can find more information on when to pick == and when to pick === here:
When is it OK to use == in JavaScript?
I would argue that any form of type coercion, if unexpected for types that may not be known at runtime (like any dynamic language) is bad practice.
For example, these are both truthy:
"0" == false
"0"
While this is falsey:
false
A falsy value is a value that translates to false when evaluated in a Boolean context.
https://developer.mozilla.org/en-US/docs/Glossary/Falsy
Exactly the following values are falsy in Javascript: false, 0, "", null, undefined, and NaN.
Now I am seeing this weird behavior: only the falsy values false, 0, and "" are equal to each other, but not equal to the other falsy values.
In addition null and undefined are not equal to any falsy values other than themselves.
And last but not least, NaN isn't equal to any falsy value, not even to itself!
Yet all of them evaluate to false in a Boolean expression like if (value) { ... }
What's the benefit or use case of this seemingly inconsistent behavior?
Note: By "equal" I mean (lax) equality defined by the == operator, rather than strict idendity defined by the === operator.
Why are falsy values not equal to each other in JavaScript?
Because there's a difference between two values that coerce to the same value when used as a boolean, and those two values being equal to one another.
What's the benefit or use case of this seemingly inconsistent behavior?
There we get into largely subjective territory, which isn't really on-topic for SO. Let's just say that JavaScript's loose equality rules have long been the subject of debate and confusion. One has to remember that they were created by Brendan Eich during those mad 10 days in May 1995 in which he created JavaScript, it's no great surprise there are some "clangers" in there. And remember his task was to create a tolerant, forgiving language for non-programmers to program in. Hence automatic semicolon conversion, loose equality, and so on. This was a language that was meant to let you grab a value from an input and treat it like a number, even though the value of an input is always a string. Whether these rules achieved that goal is a matter of opinion (and I'm not advancing one here either way :-) ).
Most of the "weirdness" comes about as a by-product of rules that mostly seem reasonable (with, again, a couple of clangers). Let's consider the thing about "" == 0 being true:
The rule for == is the abstract equality comparison algorithm, which says that if the first operand (x) is a string and the second operand (y) is a number, we return the result of ToNumber(x) == y. Leaving aside the question of whether a coercing equality operator is a good idea or not, if you're going to have one, that seems like a reasonable way to approach string == number. So we look to the ToNumber algorithm, which says that ToNumber(string) interprets the string as a number using the ToNumber Applied to the String Type algorithm, which says amongst other things that an empty string becomes 0.
So the question isn't "why is "" equal to 0", it's "why does "" coerce to the value 0 when treated as a number?" Only Eich can answer that question. :-)
There are some other fun ones in the main ToNumber algorithm, such as that undefined => NaN but null => 0. Again, only Eich can explain why he thought null should equate to 0 but undefined equate to NaN.
It's probably worth noting that he probably didn't just pick this stuff at random. He'd studied several other languages and made choices based on that knowledge. Some of those choices may look very odd to us in retrospect (implicit globals? really?), but then, most people have more than 10 days to create a language, time in which they can seek input from colleagues and the community. And again, there was that "tolerant" design criterion.
I may have strayed into some subjectiveness there. Apologies if so; I tried not to. :-)
Final note: If you find the rules arbitrary and hard to memorize, you aren't alone. One way to handle that is to ensure you do all your type coercion explicitly. But note that even if you try to do that, you're stuck with loose comparisons, because although there's a strict equality operator (===) and a strict inequality operator (!==), there are no strict versions of >, <, >=, or <=. So if you miss out an explicit coercion, your code may still seem to work if you're doing any of those other relations. I'm not advocating this (nor am I advocating against it), I've seen bugs caused both by explicit type coercion and by not having explicit type coercion. Just saying that it's one approach to the tricky rules.
It's probably related to preference. == null is very useful to determine if something is in a "not set" state, as it also checks for undefined; but does NOT return true for values like "", or 0; which will often come back from a form as valid values.
My understanding is that NaN fails all comparison checks so that it is noticed as soon as possible, so as to mean "This is not the value you were expecting." This works out if someone's type-checking block ends in an else { throw exception because I don't know what this is! }
I see no benefit to comparing false with 0, "", null, NaN, or undefined. There are no use cases, in my mind, that justify its use. If you write your code properly, this odd behavior is factored out. The reason the behavior exists in the first place is because JavaScript is loosely typed. Everything is an object. Best practice is to avoid use of the == equality operator and instead use ===.
Fundamentally, you shouldn't allow variables to be coerced into different types across the use of a program. It hinders understandability, readability, and maintainability. It's better to code Boolean operations explicitly (i.e. do this if (myVar === undefined) {...}, not if (!myVar) {...}).
To some extent the inconsistency is probably down to "Wat?!?" - see https://www.youtube.com/watch?v=FqhZZNUyVFM.
I mean, it's kind of odd that false, 0, and "" are considered equal, given they're different kinds of thing (well, I think it's odd anyway)... but I suppose this is why JS has both a strict and a lax equality operator.
And it's why tools like jshint and jslint encourage you to only use the strict === operator, so you don't fall foul of this kind of weirdness. This then forces you to test for truthiness or falsiness directly, rather than via lax equality.
Or to turn it around, if you think it's odd that falsey values aren't equal to eachother, it would be weird if this weren't the behaviour for truthy values. For example, you'd never expect "Bananas" and "Apples" to be equal.
(And, to more directly answer your question: I'd bet some weird historical reason that might get a mention in JavaScript: The Good Parts. Beyond that I don't know.)
This question already has answers here:
What's the reason to use === instead of == with typeof in Javascript?
(5 answers)
Closed 8 years ago.
In many examples of code I do see people using === when typechecking with typeof.
But typeof always returns a string. No matter which variable you are checking. So why typechecking this by using ===?
Example:
if(typeof num === 'number')
// do something
Is there any edge-case I dont know?
The typeof operator always returns a string, so the behavior will be identical. If you don't specifically need coercion, it's good practice to use the strictest available operator.
There shouldn't be a performance difference in this case, as typeof is guaranteed to return a string, so no coercion should ever be done. If someone changes the code, however, using === will force the new code to also return a string (or make them update the condition).
The == operator is useful when you need to compare two values of different (or potentially different) types, but if you know ahead of time the types will be identical, === has all the benefits and enforces strict comparison. Later on, if someone wants to make the code less strict, they have to explicitly do so.
=== is usually faster than ==.
If you compare two values while ignoring their their type (==), javascript usually has to convert one or both of the values to another type internally and do additional checks.
=== on the other hand does not have to convert anything and only has to do one comparison. So when you do not have to worry about cases like "1" == 1, === is usually faster.
In this case, as typeof always returns a string and the second value also is a string, == is not needed, so === is uses out of convention.
If there is no type conversion possible in a given comparison (which there is not with typeof x === "string" because typeof always returns a string), then there is no functional difference between == and ===. Which to use in that case is more a matter of preferred style since there is no functional difference.
So, in your case of:
if (typeof num === 'number')
there is no functional difference between that and the == version:
if (typeof num == 'number')
Either will provide the exact same result no matter what value num has. You can use either version and your code will run correctly in all cases.
Is there any edge-case I dont know?
No, there are no edge cases for this particular example.
So why typechecking this by using ===?
One popular recommendation for Javascript coding is to always use === unless you explicitly WANT a type conversion to be allowed. This is considered a safer coding style because you won't accidentally get a type conversion that you weren't thinking about or planning for.
So, if you are following this recommendation, then you get yourself in a frame of mind that your default coding style is to use === unless there is a reason NOT to use it (e.g. you want a type conversion to be allowed).
That is the opposite of your logic where you are looking for a reason to use === instead of looking for a reason not to use ==.