Typescript 101 - optional chaining

Harness the power of typescript optional chaining. It was one of the most requested features in Typescript and with version 3.7 it has finally landed...

Typescript 101 - optional chaining

This is the fourth post of a blog series where each post will touch a popular TypeScript method, function or feature with example. If you’re starting with TypeScript (or JavaScript) you might not be familiar with all of these powerful tools that can shorten your codebase and help you in day to day development

This post we will discuss optional chaining.

?

It almost looks like I forgot to add a function name or sentence above, but truly this entire post revolves around a question mark, which is the operator used in optional chaining. Consider the following array of users which is an expanded version of the previous blog post.

interface IUser {
    username: string;
    fullName: string;
    company?: ICompany;
}
interface ICompany {
    name: string;
}

const users: IUser[] = [{
        username: 'mmaas',
        fullName: 'Marcel Maas',
        company: {
            name: 'Terra10'
        }
    },
    {
        username: 'jvzoggel',
        fullName: 'Jan van Zoggel',
        company: {
            name: 'Terra10'
        }
    },
    {
        username: 'djanssen',
        fullName: 'Dirk Janssen',
        company: {
            name: 'Terra10'
        }
    },
    {
        username: 'rgoossens',
        fullName: 'Roger Goossens'
    }];

Let's say we want to find out at which company Marcel works we could do this like so:

const company = users.find(user => user.username === 'mmaas').company.name;
console.log(company);

This will print: 'Terra10'. However if we would like to find out at which company Roger works...

const company = users.find(user => user.username === 'rgoossens').company.name;
console.log(company);

We get an error:

TypeError: undefined is not an object (evaluating 'users.find(user => user.username === 'rgoossens').company.name')

This is because Roger is a "No good, hair of the dog lazy unemployed character" who has no company attribute. As you might have noticed already this is a possibility because the interface states "company" is optional. This is also denoted by a question mark.

To get around this issue in "the old days... back when Roger still had a job..." we would do something like this:

const foundUser = users.find(user => user.username === 'rgoossens');
const company = (foundUser) ? foundUser.company: undefined;
const companyName = (company) ? company.name : 'Unemployed';
console.log(companyName)

Which will result in a 'Unemployed' log message.

This is where optional chaining comes to the rescue. In practice it means when you use the ?. operator it will evaluate if the preceding statement is null or undefined and just return undefined. We would write the previous code as such using optional chaining:

const companyName = users.find(user => user.username === 'rgoossens')?.company?.name;
console.log(companyName ? companyName : 'Unemployed');

Because both the find method might return undefined, and a company might not be defined i have added the question mark in both of these location. Much cleaner and concise than before. This will also make your life a lot easer when writing if-statements. Instead of:

if (user && user.company && user.company.name) {
	// do stuff
}

You can now do:

if (user?.company?.name) {
	// do more concise stuff
}

Summary

Using optional chaining you can get rid of much null and undefined checks using if-statements or ternary expressions. Simply remember that when a null or undefined is encountered when you have used the ?. operator the entire line will return undefined. Your code will become much more readable.

Make sure to also check our other TypeScript 101 posts.

Hope it helps!