Updated Answer:
I think this recursive one liner will do exactly what you're looking for:
properties.getData = (args, data) => args.length ? this.getData(args.slice(1), data ? data[args[0]] : this.globalData[args[0]]) : data ? data : this.globalData
Call it with your infinite amount of property-arguments or array indices in an array like so:
dataService.getData(['arrayOfData', 2, 'propOnArrElement', 'subProp', 'desiredValue'])
Explanation:
The "signature" of the function would be something like
getData(args: Array, data?: any): any
,
which means:
- It takes an Array as the first argument (containing the trail of properties/indices you wish to traverse to get to your nested data)
- It takes the data structure we are querying as an optional second argument (of course, this would of necessity be an Object or an Array)
- It will return the desired piece of data, which could be any type at all.
How It Works:
When the function is called,
- the second argument should not be defined, so that the service can reach out to the globalData object, as we will see later.
- The args Array is checked for length (
args.length ?
), and
- if it has elements, the recursive call is made (
this.getData(
),
- but this time, we will drop the first arg from the args Array (
args.slice(1),
),
- and the data argument will be (re)included (
data ?
).
- If it was defined in the most recent recursive call, then the first arg element is used to access that property(or index) on the data Object/Array (
data[args[0]] :
),
- but if it hasn't been defined yet (like in the initial function call), the recursive call will use the globalData property instead (
this.globalData[args[0]])
).
- As the function continues it's recursive course, the data structure is being narrowed down to deeper levels of data, and the arguments list is dwindling.
- Once the args length resolves to false (no more args left to explore!), instead of returning another recursive call, the function simply returns the current data object (
: data ? data
).
- In the event this function was called with an empty array, the the entire globalData will be returned (
: this.globalData
).
I hope you find this helpful, or at least enjoyable reading. I was sure excited when this solution popped in my head while showering tonight. :P
Bonus Material
Here is a similar (even better) approach, using ES6 rest parameters and Array.reduce (this will allow you to call the function without passing an array):
properties.getData = (...args) => args.reduce((data, arg) => data[arg], this.globalData)
call like so:
dataService.getData('firstarg', 'secondarg', 'onemorearg', 'desireddata')
Original, dissatisfying answer:
Since you return the data, you could simply access the property directly on the function invocation:
const nestedVal = dataService.getData(‘foo’).bar
Or:
const nestedVal = dataService.getData(‘foo’)[‘bar’]