1
\$\begingroup\$

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?

asked Sep 25, 2020 at 3:28
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

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.

answered Sep 25, 2020 at 3:33
\$\endgroup\$
1
\$\begingroup\$

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 returns undefined
  • 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.

answered Sep 25, 2020 at 4:49
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.