DEV Community

loading...

Optional handmade chaining

wakeupmh profile image Marcos Henrique 1 min read

In my country (Brazil) we have a saying, who doesn't have a dog hunting with a cat.

I've been working on a project where we could not update the latest version of the node and there was no possibility to put the babel or even the experimental flag --harmony, because we had some enterprise restrictions to do something like that.

So it's time to use creativity

const optionalChainingByPath = (object, path) => {
  const pathSplitted = path.split('.')

  const [firstKey] = pathSplitted

 if (object[firstKey] == null || object[firstKey] ==='' ) { return null }
  if (typeof object[firstKey] === 'object') {
    pathSplitted.shift()
    return optionalChainningByPath(object[firstKey], pathSplitted.join('.'))
  }

  return object[firstKey]
}

Enter fullscreen mode Exit fullscreen mode

Usage:

const makeResponse = patient => ({
  name: optionalChainingByPath(patient, 'personalInformation.name'),
  gender: optionalChainingByPath(patient, 'personalInformation.gender'),
  cardNumber: optionalChainingByPath(patient, 'personalInformation.cardNumber')
})
Enter fullscreen mode Exit fullscreen mode

It's ok but unamused

Let's make this cool enough 戊

We'll use partial functions to transform this boring function into a fancy function

const optionalChainingByPath = object => path => {
  const pathSplitted = path.split('.')

  const [firstKey] = pathSplitted

  if (object[firstKey] == null || object[firstKey] === '') {
    return null
  }

  if (typeof object[firstKey] === 'object') {
    pathSplitted.shift()
    return optionalChainingByPath(object[firstKey], pathSplitted.join('.'))
  }

  return object[firstKey]
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const makeResponse = patient => {
  return {
    name: optionalChaining('personalInformation.name'),
    gender: optionalChaining('personalInformation.gender'),
    cardNumber: optionalChaining('personalInformation.cardNumber')
  }
}
Enter fullscreen mode Exit fullscreen mode

Does sounds like a charm or doesn't?

Discussion (7)

pic
Editor guide
Collapse
andrewbridge profile image
Andrew Bridge

Always fun to work through these problems as a learning experience, but here's another implementation, based on the lodash get method.

github.com/cedmax/youmightnotneed/...

The same GitHub repo has examples of set and has implementations.

Collapse
wakeupmh profile image
Marcos Henrique Author

Awesome tip fude, thank u for sharing

Collapse
felipperegazio profile image
Felippe Regazio • Edited

Really cool solution, it does look like a charm : )
You can also extract the object value in a functional style with:

const optionalChaining = (obj, str) => (obj && str) && (() => str.split('.').reduce((o, i) => o[i], obj))();
Enter fullscreen mode Exit fullscreen mode

and use like that:

const letters = { a: { b: 'c' } };

optionalChaining(letters, 'a'); // {b: "c"}
optionalChaining(letters, 'a.b'); // 'c'
optionalChaining(letters, 'a.b.e'); // undefined
optionalChaining(letters, 'z'); // undefined
Enter fullscreen mode Exit fullscreen mode

We can also extend the Object prototype to avoid some problems (dont know about how good or bad it could be in terms of design, but its possible):

Object.prototype.optionalChaining = function (str) {
  return str.split('.').reduce((o, i) => o[i], this);
}

const letters = { a: { b: 'c' } };

letters.optionalChaining('a'); // {b: "c"}
letters.optionalChaining('a.b'); // 'c'
letters.optionalChaining('a.b.e'); // undefined
letters.optionalChaining('z'); // undefined
Enter fullscreen mode Exit fullscreen mode
Collapse
wakeupmh profile image
Marcos Henrique Author

Clean and beauty, thanks bro

Collapse
olavoparno profile image
Olavo Parno

If Node's new stuff doesn't come to you, then move YOUR VERY SELF to Node's new stuff haha

Collapse
wakeupmh profile image
Marcos Henrique Author

Suhsiajaidjdi it's ALL folks xD

Collapse
ecyrbe profile image
ecyrbe • Edited

Here is another way based on proxy that that feels more native