🛡️ How to safely access deeply nested values in javascript?
Tags: javascript, beginners
Published: 2019-09-05 15:56:10

I would like to share a problem I had today and how I solved it. It is about the way to access deeply nested values in javascript. Here is a simple example :

```javascript
const options = {
    notification: {
        enablePrivateMessage: true,
        enableCommentResponse: false
    }
}

const enablePrivateMessage = options.notification.enablePrivateMessage
const enableCommentResponse = options.notification.enableCommentResponse 
```

## What's the problem ? 

This works fine, however what's happen if `options` or `notification` are `undefined` ? 
```javascript
const options = undefined
const enablePrivateMessage = options.notification.enablePrivateMessage
// Uncaught TypeError: Cannot read property 'notification' of undefined

const options = {}
const enablePrivateMessage = options.notification.enablePrivateMessage
// Uncaught TypeError: Cannot read property 'enablePrivateMessage' of undefined

```

Yep, that's embarrassing ! It's not safe to access deeply nested values if you're not sure that the intermediate values are set. In the previous example, I tried to access the property `enablePrivateMessage` of `notification`, but unfortunately `notification` has not been set in `options` and consequently is equal to `undefined`. The error message tells me that I tried to access `enablePrivateMessage` propery from something `undefined`.

## How to solve it ?

A first solution to this problem could be to browse nested properties one at a time and check if their values are `null` or `undefined` before accessing to the following nested value.

```javascript
const options = {}
const enablePrivateMessage = options && options.notification && options.notification.enablePrivateMessage 
// enablePrivateMessage == undefined

// alternative way
const enablePrivateMessage = !options ? 
    undefined : !options.notification ? 
        undefined : options.notification.enablePrivateMessage 
// enablePrivateMessage == undefined
```

Although this works for simple cases, it could be painful to write that if your object is very depth. The code would be very long and difficult to read. Fortunately as the same way as [lodash `get` function](https://github.com/lodash/lodash/blob/master/get.js), we can design a function to safely access properties. Here it is :
```javascript
export const getPropValue = (object, path = '') =>
    path.split('.')
        .reduce((o, x) => o == undefined ? o : o[x]
        , object)

const options = {}
const enablePrivateMessage = getPropValue(options, 'notification.enablePrivateMessage')
// enablePrivateMessage == undefined
```

How does it work ? `getPropValue` is a function that takes two parameters. The first one is the `object` to query and the second one is the `path` to a nested prop we hope to find. When the function is executed, we split the path in an array in order to get all nested properties to browse. 
```javascript
// Example
// path = 'notification.enablePrivateMessage'
'notification.enablePrivateMessage'.split('.')
// ['notification', 'enablePrivateMessage']
```


Finally we execute a [`reduce`](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce) function from that array with an aggregator initially set with the object to query. The `reduce` function browses all properties in the path and if one of these have an undefined value, then the result will be `undefined`. Otherwise the value of the nested prop is returned.
```javascript
// Example 1 : All properties are defined in the path
// object = {notification: {enablePrivateMessage: true}}
// path = 'notification.enablePrivateMessage'
['notification', 'enablePrivateMessage'].reduce((o, x) => {
    console.log(o, x)
    return o == undefined ? o : o[x]
}, {notification: {enablePrivateMessage: true}})
// {notification: {enablePrivateMessage: true}} 'notification'
// {enablePrivateMessage: true} 'enablePrivateMessage'
// true

// Example 2 : notification is undefined
// object = {}
// path = 'notification.enablePrivateMessage'
['notification', 'enablePrivateMessage'].reduce((o, x) => {
    console.log(o, x)
    return o == undefined ? o : o[x]
}, {})
// {} 'notification'
// undefined
```

## What's about ES6 destructuring ?

Well, that's good ! But since ES6, destructuring feature is available in Javascript. This feature is really nice and allows developpers to easily declare and set variables with the nested properties of an object.
```javascript
const options = {
    notification: {
        enablePrivateMessage: true,
        enableCommentResponse: false
    }
}

const {notification: {enablePrivateMessage, enableCommentResponse}} = options

console.log(enablePrivateMessage)
// true

console.log(enableCommentResponse)
// false
```

However, I cannot use my `getPropValue` function in this case. If `options` is `undefined`, then the previous destructuring will result an error.
```javascript
const options = undefined
const {notification: {enablePrivateMessage, enableCommentResponse}} = options
// Uncaught TypeError: Cannot destructure property `notification` of 'undefined' or 'null'.
```

A simple way to protect our code against that error is to set a fallback value if `options` is `undefined`. But it is not enough.
```javascript
const options = undefined
const {notification: {enablePrivateMessage, enableCommentResponse}} = options || {}
// Uncaught TypeError: Cannot destructure property `enablePrivateMessage` of 'undefined' or 'null'
```

Once you did that, you need to set default values for all your nested properties before to get the wanted properties.
```javascript
const options = undefined
let {notification: {enablePrivateMessage, enableCommentResponse} = {}} = options || {}

console.log(enablePrivateMessage)
// undefined

console.log(enableCommentResponse)
// undefined
```

This is not as convenient as `getPropValue` function if the properties you want are very depth. In this case, you should consider that destructuring may not be the best way to access your properties because your instruction will be too long to be readable. In this case I recommand to access your properties one at a time with `getPropValue` function.

## Lodash can help you !

You should know that `getPropValue` is a function I designed for this post. In real life I use the [lodash `get` function](https://lodash.com/docs/4.17.11#get). It is really usefull in many cases and work likely `getPropValue`. There is an extra parameter that allow you to set a fallback value if your path reach an undefined value before to get the targeted property.
```javascript
import { get } from 'lodash'

const options = {
    notification: {
        enablePrivateMessage: true,
        enableCommentResponse: false
    }
}

// Example 1 : Simple case
get(options, 'notification.enablePrivateMessage')
// true

// Example 2 : Error case with 'fallback' as fallback value
get(options, 'toto.tata', 'fallback')
// 'fallback'
```

And that's it! You know all you need to know to safely access deep nested values in javascript! Hope you enjoyed my first post in [dev.to](https://dev.to)!