Checking for null and undefined is a common task in TypeScript (and JavaScript in general), and there are several ways to do it. In this article, we’ll explore some of the most common techniques for checking null and undefined values in TypeScript.

Equals

The most straightforward way of checking is of course the equality operator

const myValue = maybeNullOrUndefined();

if (myValue === null) console.log('Null!');
if (myValue === undefined) console.log('Undefined!');

You might notice I’ve used “===” here, which is the strict equality operator. The difference here is that “===” as a stricter operator, will specifically check for null or undefined.

Let’s take a look at this function, which uses the regular equality operator “==” instead of the stricter variant:

function checkValue(value: number | null | undefined) {
    console.log(value);
    if (myValue == null) console.log('Null!');
    if (myValue == undefined) console.log('Undefined!');
}

checkValue(null);
checkValue(undefined);

With regular equality “==”, here’s what we get:

The normal, loose equality operator specifically handles this case. If one of the values on either side is null or undefined, if the other one is null or undefined, then they’re equal.

In a lot of scenarios this might not matter, you might just be checking if a variable has a truthy value. In that case you can safely use the regular equality operator. You can also shorten your code, to something like:

function checkValue(value: number | null | undefined) {
    console.log(value);
    if (!myValue) console.log('Null or undefined (doesnt matter)');
}

checkValue(null);
checkValue(undefined);

But there is a difference between null and undefined, and you might want to handle that separately in some cases. Null often means something is specifically meant to have no value, whereas undefined tends to mean something hasn’t been given a value yet.

An example might be something like if you’re using a function to fetch some data. Null might mean the search has been completed, but the data wasn’t found, whereas undefined might indicate that the fetch was never completed successfully.

Coalescing Operator

Another way to check for null or undefined is to use the nullish coalescing operator (??), which was introduced in TypeScript 3.7. This operator returns the left-hand side of the expression if it’s not null or undefined, and the right-hand side otherwise:

const var1 = null ?? 'Pick me!';
const var2 = undefined ?? 'Pick me1';
const var3 = 'Now pick me!' ?? 'Not me';
console.log(var1, var2, var3);

Here’s what we get outputted:

The most common use case for this is for default values, something like:

const username = fetchUsernameMightfail() ?? 'default_username';

You might see this a lot for things like environment variables:

const API_URL = process.env.API_URL ?? 'http://localhost:1707';

I.e. if we get API_URL as an environment variable, use that value, but otherwise default to the value on the right.

As well as the null coalescing operator, you might also find the less commonly used Nullish coalescing assignment operator:

let var1 = null;
var1 ??= 'Replacing null';
var1 ??= 'Wont pick me (var1 isnt null)'

In the example above, var1 starts off as null. The next assignment does store the string in var1, since var1 is null. Then since we have ‘Replacing null’ in var1 now, the next assignment gets skipped.

This can be used to assign a value only if the variable is null. It’s less commonly seen, but you might still run into it.

Optional Chaining

Another shortcut TypeScript provides for checking for null or undefined is optional chaining. It’s used for accessing properties of an object that might be undefined or null.

Let’s take this type:

type MyUser = {
    name: string;
    friends?: MyUser[];
    delete: () => void;
}
const myUser: MyUser | null = getUser();
//TS18047: 'myUser' is possibly 'null'.

We get an error with this code, since unfortunately, our user might not exist.

So we could use one of the approaches we’ve learnt before, and check beforehand:

if (myUser) myUser.delete();

But with optional chaining, we can shorten this to:

myUser?.delete();

And as you can work out from the name, we can chain this as much as we need to:

myUser?.friends?.[0].delete();
myUser?.friends?.[0]?.friends?.[0].delete();
myUser?.friends?.[0]?.friends?.[0]?.friends?.[0].delete(); //etc

As soon as one part fails, the chain won’t continue.

Conclusion

Thanks for reading! Checking for null and undefined values is an important task in TypeScript. By using the techniques we’ve gone over, you can ensure that your code behaves as expected even when dealing with null and undefined values.

Remember to choose the technique that fits your code best, bearing in mind whether or not you need your code to discern between “null” and “undefined”. If you’re interested in further reading, why not delve further into the rest of TypeScript’s primitive types.

If you liked this article, feel free to leave a comment below!

Avatar photo
👋 Hey, I'm Omari Thompson-Edwards
Hey, I'm Omari! 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, reach out on Twitter at @marile0n

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.