DEV Community

Cover image for TypeScript object destructuring and you
Megan Lee for LogRocket

Posted on • Originally published at blog.logrocket.com

TypeScript object destructuring and you

Written by Lewis Cianci✏️

Javascript has been around for quite some time, first coming out almost 30 years ago. Because of its rich history, it’s gathered quite a bit of functionality over the years.

More recently, in about 2012, TypeScript attempted to give types to JavaScript. Fortunately, because developers are a relatively unopinionated bunch (and easily agree on everything) there hasn’t ever been much furor on the JavaScript vs. TypeScript debate. Not.

Whether you’re part of the typed club or not, one function within TypeScript that can make life a lot easier is object destructuring. TypeScript object destructuring is a bit of a weird one; sometimes you can listen to what something is and assume a certain functionality.

For example, you know what a promise is, or an observable. But destructuring? It doesn’t lend itself to a credible idea of what it actually is.

What is object destructuring?

I went literally years without ever using object destructuring, so if you’re not immediately aware of what it is or why you’d want to use it, that’s okay.

However, now that I know about it, it makes my life dramatically easier when dealing with operators that take an input and produce other variables. For example, an observable may emit many values that go through a pipe, and with each operator, it could get harder to work out exactly what variable is where in the subsequent responses.

That specific use case we’ll get into a little bit later. For now, let’s start slow and use simple examples to understand how they work.

Consider this humble array:

let simpleArray = [1,2,3,4,5];
Enter fullscreen mode Exit fullscreen mode

If we wanted to get the first two values of this array, typically we could use slice or some other operator. But with destructuring, we can do this instead:

const [a,b] = simpleArray
Enter fullscreen mode Exit fullscreen mode

It feels weird assigning bits of an array to our const, but we’re actually just popping out the first two values of that array and assigning it to a and b. If we wanted to access the remaining values, we could even do something like this:

const [a, b, ...remaining] = simpleArray
Enter fullscreen mode Exit fullscreen mode

That’s a nice way of seeing how destructuring works, but it also seems a bit pointless. If you saw that in a vacuum, you’d likely think it was like slice but with more steps. You’d be forgiven for thinking that.

A more complex example of object destructuring

As developers, a lot of our complexity can come from things happening at some point in the future. Of course, there is the humble Promise, or asynchronous object that returns at some point in the future. But before long, we’ve graduated to [Observables](https://blog.logrocket.com/guide-rxjs-observables/) and a temporal element is introduced. These things emit over time, baby.

Would we encounter these every day as a developer? Well, if you have a form on your website where people can enter data, and they can view results, what are our sources of events? There’s the user clicking on the search button; that’s true. But what about sorting and filtering the data? It would be nice to do this all out of the one Observable and not stash our half-sorted array into a temporary variable while we’re working it out.

That’s such a good application for destructuring. Let’s see why.

Let’s start out by subscribing to a sortOrder variable. This is the name of the header that the data would be sorted by. In our handy-dandy editor, it tells us the type of data that will come from this Observable, as suggested by the type system: subscribing a sortOrder variable typescript object destructuring Unsurprisingly, it’s an Observable<string>. It’s going to emit over time when someone clicks on the Sort Order button. But, we want to combine this observable with other observables. What happens when we do that?: combining observables typescript object destructuring

Ah that’s not very…. descriptive. Now it’s an Observable of type string, string. TypeScript pulls this variable out of thin air as it describes our data shape.

Annoyingly, we’d have to access the values in this by using an index, so we’d have to remember when we assigned each variable in the pipe operator. For reasonably complex pipe() chains, before long we’d look like this: meme of assigning variables to pipe operator

Where this gets really exciting is that, with each subsequent call to combineLatestWith, we receive our original tuple, with the newest combineLatestWith value tacked on the end.

Rapidly this descends into chaos as our type information gets truncated due to the sheer length: truncated type information typescript object destructuring Hovering over the object to see the type shows us what we’re dealing with: hovering over object in observable chain

This does not spark joy.

If we had some sort of even more complex system, and we had to listen to many Observables to produce a result, then it wouldn’t be so hard to imagine a deeply, deeply nested set of tuples and objects. And we’d have to pluck them out by index.

So basically, just surround the whole code block with “NEVER REFACTOR THIS YOU WILL BE FIRED” and move on with your life.

Fortunately, destructuring can really help with this proposition.

Let’s dummy up a simple HTML table with a few fields, and sorting: Simple Dummy HTML Table For Typescript Object Destructuring

We use forms that are at least this complex in the day-to-day, but there’s quite a bit going on here. We want to react instantly when someone presses the Search button, and the Sort button… but we also want to take the latest values from other fields, like the name or profession input boxes.

Fortunately, we can use RxJS operators to achieve just this:

this.tableData$ = this.sortOrder.pipe(
  combineLatestWith(this.header),
  combineLatestWith(this.searchButton$),
  withLatestFrom(this.formGroup.valueChanges)
) 
Enter fullscreen mode Exit fullscreen mode

But after, we want to use a switch map to terminate any in-flight requests if new requests come through. What’s the signature of the object that is passed into the switchMap operator though?: signature of object passed into switch map For every new RxJS operator we use, it gets wrapped in a tuple. So, imagine that we have a data source (like an HTTP API for example) that has a signature like this:

fakeAsyncronousDataSource(name: string, profession: string, header: Header | undefined, sortOrder: SortOrder, page: number)
Enter fullscreen mode Exit fullscreen mode

Our entire chain winds up looking like this:

this.tableData$ = this.sortOrder.pipe(
  combineLatestWith(this.header),
  combineLatestWith(this.searchButton$),
  withLatestFrom(this.formGroup.valueChanges),
  switchMap(x => {
    return this.fakeAsyncronousDataSource(x\[1].name ?? '', x[1].profession ?? '', x[0\][0]\[1], x[0\][0][0], 0)
  }),
  startWith(testData.slice(0, 10))
)
>
Enter fullscreen mode Exit fullscreen mode

Imagine trying to present that straight-faced at a code review.

“Oh and this is the bit where I pull values out of a tuple layered three layers deep and pass it to a function. I do it entirely using index values that I and only I know when I wrote the code”.

And then the laughter gives way to long stares as they realize — you’re actually being serious. No no, let’s not be that person.

TypeScript object destructuring to the rescue

Fortunately, we can “unwrap” the layered tuple by using TypeScript object destructuring. It’s kind of a quick transition, but our RxJS chain now looks like this:

  this.tableData$ = this.sortOrder.pipe(
    combineLatestWith(this.header),
    combineLatestWith(this.searchButton$),
    withLatestFrom(this.formGroup.valueChanges),
    switchMap(([[[sort, header], _], formData]) => {
      return this.fakeAsyncronousDataSource(formData.name ?? '', formData.profession ?? '', header, sort, 0)
    }),
    startWith(testData.slice(0, 10))
)
Enter fullscreen mode Exit fullscreen mode

This has many benefits.

First, and most obviously, we know what the variables are when they are used in the function call. We don’t have to pluck values out by index, so readability improves substantially.

Secondly, we can mentally associate each tuple value in the destructuring to the respective pipe operators before it. So, if we want to add things to the pipe, it’s not a huge inconvenience.

To be fair, normally it takes quite a long tour-de-force through a language feature to really tease out its benefits. But, in this case, it’s fairly obvious. When you have a complex type that is being produced by something like an observable chain, don’t be afraid to reach for something like destructuring.

Conclusion

In this article, we learned how to destructure objects in a wide variety of cases. We saw how they could be used in arrays, but also how they could be used in an Observable chain. However we use them, they help us to write clean, maintainable code.

Feel free to clone the sample on GitHub here. After you have done so, and have started the project, you can also access the simple example on http://localhost:4200/simple, and the complex example on http://localhost:4200/complex, respectively.


LogRocket: Full visibility into your web and mobile apps

LogRocket Typescript Demo

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

Try it for free.

Top comments (0)