JavaScript and TypeScript Tips
Spreading, Resting, and Renaming Properties in TypeScript
When you need a new object that is a close relation to an existing object but one or more of the property names must change.
I first saw this technique in this excellent post by Joel Thoms. That article has a collection of tips. I just wanted to focus on this one technique, and provide a more robust explanation.
Real-World Need
While my example code is very slimmed down this technique did have roots in a real-world need. We were writing an API call to return a single object that we wanted to construct from some existing objects. The problem we had is that one recalcitrant property from one of the objects needed to be renamed.
For this discussion, assume we have an object that conforms to the following interface:
and instead of a property with the name z
we need a property named zed
we can use this simple fat arrow function to accomplish that:
This one line of code contains a lot of buzzwords, so let’s walk through this. We are defining a function named renameZed
it takes a single parameter that is an object. The parameter is using “de-structuring” to separate that argument into two pieces. The first de-structured item is peeling the property z
off of the object. The second de-structured item is using the “rest” operator ① to get the remaining properties into an object named remainder. I have always found the name “rest” confusing here due to the homonymic collisions with the REST acronym and the verb “rest”. I used the variable name remainder to make it clearer that “rest” means “the rest of the stuff”.
After the fat arrow we need a set of parentheses, since we aren’t using the “return” keyword and braces. We start our return object with a pair of braces and specify the first property as zed.
The original object’s z
property value is assigned to to zed
. Next, the “spread” operator ② is used to add back all of the remaining properties from the original object. We get back our desired object that conforms to this interface:
A test for this code could look like this:
The only thing missing now are the types. While I could have just created the interface FinalLetters
as shown above, this example is much simpler than a typical object and even when creating types I want to be as DRY as possible.
Here I’m creating the type RenamedZed
and specifying that it has all the properties of the Letters
interface EXCEPT for the z
property. The TypeScript utility Omit
does the job for that. Then I use &
to combine the subset of Letters’
properties with my new zed
property to form an Intersection Type. If you are confused by why this is an intersection type and not a union type, this article may help some. My suggestion is to just focus more on the fact that the &
operator combines the two sets of properties together and worry about set theory semantics later.
If you find you not only need to rename properties but remove one or more properties, this story now has a second chapter.
The code shown in this article is available in GitHub.
There are more JavaScript and Typescript tip articles.
Code in peace.