So I'm parsing an object using Typescript. I am pushing a value from within the object into an array of strings.
Here's the code:
if (data.InstanceStatuses != undefined)
if (data.InstanceStatuses[0].InstanceId != undefined)
instanceIds.push(data.InstanceStatuses[0].InstanceId as string)
I feel there must be a better way to deal with the fact that both data.InstanceStatuses
and data.instanceStatuses[0].InstanceId
can be of type string || undefined
, however I am not sure how to get it down to a simpler statement with less IF blocks.
Any ideas?
2 Answers 2
Typescript has supported optional chaining for a while. To do this concisely and avoid the somewhat inelegant as string
type assertion, extract the possibly nested value into a variable, then check its typeof
against string
:
const instanceId = data.InstanceStatuses?.[0].InstanceId;
if (typeof instanceId === 'string') {
instanceIds.push(instanceId);
}
This way, instanceId
will be either the nested value, or, if InstanceStatuses
doesn't exist, it'll be undefined
. So, it'll only push to the array if the nested value exists and the value is a string.
An alternative to optional chaining is to make something like this:
const optionalChaining = (obj: Object, ...props: string[]) =>
props.reduce((o: any, prop: string) => (o || {})[prop] , obj);
That is:
- Try to access the
prop
in every iteration, even if it returnsundefined
- In case the previous iteration returned
undefined
, just create an object on the fly to not throw an Error because you're trying to access props of undefined.
See how Array.prototype.reduce() works, but I like to think that you can use when you want transform an array in one value.
In this case, you want to get an array of props, and get the "chained value" of them or undefined
if there's not a valid prop among them.
You could use it like:
const optionalChaining = (obj: Object, ...props: string[]) =>
props.reduce((o: any, prop: string) => (o || {})[prop] , obj);
const foo = {
data: {
InstanceStatuses: [
{ InstanceId: 'bar' }
]
}
};
console.log(
optionalChaining(
foo,
'data',
'InstanceStatuses',
'0',
'InstanceId'
)
);
console.log(
optionalChaining(
foo,
'data',
'InstanceStatuses',
'1',
'InstanceId'
)
);
The advantage is that Array.prototype.reduce
has a good browser compatibility, in other words, is a better cross-browser solution, but I would prefer optional chaining syntax when it will has a good major browsers support.
By other hand, maybe Babel could be useful if browser compatibility matters for you.