Why use triple-equal (===) in TypeScript?

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:

  1. comparing different types with == can lead to unexpected type conversions.
  2. 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.