The undefined type can be checked directly by referring to its globally available value via the strict equality operator:
if (value === undefined) {
// ...
}
Unfortunately, however, since undefined can be overridden within non-global scopes (depending on your precise setup and environment), this approach can be troublesome. Historically, undefined could be overridden globally. This meant that things like this were possible:
let value = void 0; // <- actually undefined
let undefined = 123; // <- cheeky override
if (value === undefined) {
// Does not occur
}
The void operator, as we will explore later, takes one operand to its right-hand side (void foo) and will always evaluate to undefined. As such, void 0 has become a synonym for undefined and is useful as a substitute. So, if you have low confidence in the undefined value, then you can simply check for void 0 like so:
if (value === void 0) {
// value is undefined
}
Various other approaches emerged to ensure a reliable undefined value. One, for example, would simply declare an unassigned variable (which will always default to undefined) and then use that within the scope:
function myModule() {
// My local `undefined`:
const undef;
void 0 === undef; // => true
if (someValue === undef) {
// Instead of `VALUE === undefined` I can
// use `VALUE === undef` within this scope
}
}
Over time, the mutability of the undefined value has been locked down. ECMAScript 2015 forbade global modification, but curiously still allowed local modification.
Thankfully, it has always remained possible to check for undefined via the simple typeof operator:
typeof undefined; // => "undefined"
Using typeof in this way is far less risky than relying on undefined as a literal value, though with the advent of linting tools, it is generally safe to directly check for undefined.