TypeScript
Demystifying TypeScript: The Difference Between == and === Explained
In TypeScript, the choice between "==" and "===" for equality comparison is more than just a matter of syntax—it holds significant implications for code behaviour. Despite their apparent interchangeability, these operators harbour nuanced differences that developers must grasp to write robust and maintainable code. In this article, we'll delve into the two operators, what they mean, and when to use each.
TypeScript types vs JavaScript types.
Something important to note here is what types mean for TypeScript, and what types mean for JavaScript during runtime.
JavaScript only has 8 primitive types, which are:
- String
- Boolean
- Number
- BigInt
- Null
- Undefined
- Symbol
- Object
Even if you define other types using TypeScript, when you run your code, these are all the types that exist.
Strict Equality Operator.
We'll talk through the strict equality operator first, as that's a little more straightforward.
It works like this:
- If the two operands are different types, they aren't equal and we return false
- If the two operands are objects/arrays, they're compared by reference, i.e. they have to both refer to the same array
- "NaN" is never equal to anything, even itself
- Everything else (numbers, booleans and strings) are compared by value.
It's important to remember though that this is referring to runtime JavaScript primitive types. Let's take a look at what this means with an example.
We'll define two types:
type TypeA = {
foo: string;
};
type TypeB = {
bar: string;
};
There's no overlap with their properties - very clearly different types. Let's check that with a function:
function sameType(a: TypeA, b: TypeB) {
return typeof a === typeof b;
}
But if we call our function:
console.log(sameType({ foo: '' }, { bar: '' }));
Even though TypeA does not equal TypeB we still get true. We can see why if we print the types:
TypeScript doesn't exist at runtime - during runtime, they're both just objects.
Thankfully TypeScript does warn you if you are checking if two types with no overlap won't be equal:
function areEqual(a: TypeA, b: TypeB) {
return a === b;
//This comparison appears to be unintentional because the types 'TypeA' and 'TypeB' have no overlap.ts(2367)
}
And if we change our types slightly:
type TypeA = {
foo: string;
};
type TypeB = {
foo: string;
bar: string;
};
The error disappears. This is because of JavaScript's dynamic typing - a can have fields other than the types in TypeA.
const secretlyB: TypeB = { foo: '', bar: '' };
const b: TypeB = { foo: '', bar: '' };
areEqual(secretlyB, b); //✅
Loose Equality Operator.
If the operands have the same type, this is identical to the strict equality operator.
Otherwise:
Firstly, "null" is considered equal to "undefined", since they both "loosely" represent nothing.
Then if one of the operands is an object/array and the other is a primitive, the object/array is converted to a primitive
Following this, there are a few rules for comparing different primitives:
- Booleans are converted to numbers, i.e. true is converted to 1, and false is converted to 0.
- Then the comparison is done again.
- For comparing strings and numbers, the string is converted to a number.
- If the string cannot be converted to a number, this results in NaN, and just like before the result is always false
When does this matter?
TypeScript will warn you if you are comparing types that are incompatible. This means if you are using strict types, the difference between the two operators matters a lot less. As a general rule however, you will probably want to use the strict equality operator, to avoid any implicit type conversions happening that can cause unexpected behaviour.
Conclusion.
So to sum everything up:
"===" is the strict equality operator, and checks if values are the same type before checking if they are equal
Types here mean runtime primitive types, which aren't the same as TypeScript types. Two variables can have different TypeScript types even if they are the same type during runtime.
"==" is the loose equality, or just equality operator, and generally will try to convert values to the same primitive type before comparing them
In most cases, you probably want to use the strict equality operator, and if you're using a linter it's likely to warn you about using the loose equality operator.
Thanks for reading! If you liked this article, feel free to share it!
read more.
I'm a full-stack developer from the UK. I'm currently looking for graduate and freelance software engineering roles, so if you liked this article, feel free to reach out.