Accessing Deep Properties in TypeScript

By Ilyas Assainov / In TypeScript / December 27, 2019
A

In this article, we are going to discover a few ways to access a deep object with optional properties. The scenario is if the property is undefined, we want to assign it a default value.

Let’s say we have an object with an interface like this:

interface IData {
    propertyA?: {
    propertyB?: {
        propertyC?: {
        propertyD?: string;
        };
    };
    };
}

const data: IData = {
    propertyA: {
    propertyB: {
        propertyC: {
        propertyD: 'deep property value',
        },
    },
    },
};

And we want to access propertyD:

const propertyD = data.propertyA.propertyB.propertyC.propertyD || 'default value';

If the tsconfig has a strictNullChecks or strict set to true (which it should), the TypeScript compiler won’t let us run the code.

In this case, we will need to validate the that the property exists:

let propertyD = 'default value';
if (data && data.propertyA && data.propertyB && data.propertyC && data.properyD) {
    propertyD = data.propertyA.propertyB.propertyC.propertyD;
}

As you can see, that quickly becomes cubersome. Let’s explore other choices.

Lodash Get

import get from 'lodash.get';

const propertyD: string = get(data, ['propertyA.propertyB.propertyC.propertyD'], 'default value');

The issue here is that there is no type inference and propertyD might not be a string at the end. So, using this method doesn’t give much safety.

TypeScript Optional Chaining

TypeScript 3.7, which has been released in November 2019, introduced TypeScript Optional Chaning. This is exactly what we are try to solve here.

The syntax is:

const propertyD = data?.propertyA?.propertyB?.propertyC?.propertyD || 'default value';

If the optional chain breaks, meaning some property is null, the expression will return undefined.

As you can see it looks very similar to what we had with pure JavaScript, but in this case the compiler will pass our code!

There is one caveat though, which I experienced myself. You need to have the VSCode with TypeScript 3.7. Otherwise, you will get a syntax error.

To check the version, press Shift + + P and choose Select TypeScript Version. If the version is old, update VSCode or install the extension JavaScript and TypeScript Nightly.

As you can see that’s a lot of work, which needs to be synced across your team. Therefore, there is another option.

DeepPropertyAccess

The next candidate is a type-safe Deep Property Access. Attributes to miloszpiechocki, who implemented the initial idea.

This is the second best implementation I found after TypeScript Optional Chaining because it comes with type-checking and intellisense support.

As such, if you frequently have new people in the team, it might better to use this option due to backwards editor compatibility.

Deep Property Access Intellisense Support

Usage

Copy-paste this implementation in your project, and use it like so:

import { DeepPropertyAccess } from 'path-to-module';

const propertyD = DeepPropertyAccess.get(data, 'propertyA', 'propertyB', 'propertyC', 'propertyD') || 'My default value';

In this post, we had a problem of TypeScript compiler not allowing us to use nullable properties in the object. Therefore, we went on to explore different options. The built-in JavaScript solution was too lengthy while Lodash’s get helper didn’t provide type-safety. We ended up looking at TypeScript’s new feature Optional Properties as well as Deep Property Access - solution published by miloszpiechocki. Finally we went on with the latter option because TypeScript’s Optional Chaining is not yet widely supported in people’s IDEs.

Get notified about new articles without spam!

Ilyas Assainov

Ilyas Assainov

Ilyas is a full stack developer specializing in extensible JavaScript solutions. In this blog, he shares his daily challenges and solutions.

extensive.one © 2020 - by Ilyas Assainov