Type Transformations Workshop (8 exercises)
solution

Remapping Object Keys in a Mapped Type

Here's the solution to this challenge:

Let's break it down.

The as keyword

This is the first appearance of the as keyword in this workshop.

You might have seen it used like const num = 1 as number, where it is attached to a runtime variable. TypeScript reuses the as syntax in different places, and it does different things.

In the solution to this challenge, we are using as with a key mapper. This gives us access to the original key from Attributes, while also allowing us to use it in a template literal.

Here we use a template literal to add the get prefix and the Capitalize string utility type to remap the key:

If we didn't capitalize the first letter of K we would end up with getname instead of getName.

Experiments

There are a couple of experiments to demonstrate more about how this technique works.

Remap Multiple Properties to One Key

The keys can be changed to anything that we'd like. For example, we could set every key to "wow":

Remapping multiple properties to the same key has an interesting effect.

Hovering over AttributeGetters, we can see that we are now getting a function that can return multiple types:

Manually Passing a Union

Similarly to what we saw before, we can manually pass in a union instead of using keyof and as:

This does give us a solution that would have our tests pass.

However, using keyof is great because it gives us the ability to remap the keys of any object to whatever we would like.

Transcript

[0:00] [0: 00] Let's examine this solution here. The only new thing that we've got is this as here. The as is basically acting like a key remapper. If we remove this, we end up with the type that we are grabbing from here and the solution that we had before.
[0:17] [0: 17] After this, we get to remap the keys as something new. We can change this to wow, if we like. We're going to get an interesting situation, because we're remapping multiple things to the wow. We end up with a function that can return string or number, which is interesting in itself.

[0:34] [0: 35] You might have seen this as before as const num = 1 as number for instance or as unknown or things like this. You've seen as kind of this attached a runtime variables, but it can also be attached here. TypeScript has this funny habit of reusing different syntax in different places. Here, as is doing one thing. Here, as is doing a different thing. Good on you TypeScript.

[1:03] [1: 04] We've got this as and what it's doing then is we're basically saying, OK, we get to have our cake and eat it too here, because we get access to the original key. This is going to be first name, last name, or age, which means we can still grab attributes K here, which is really critical, but we also get to remap it to something else.

[1:25] [1: 25] What's going on here is we're creating a template literal. We've got our K inside here, and if we had this like this, then we would have get lower case firstName, get lower case lastName, get age, but we're wrapping this in capitalize, meaning that we get a nice camel case read out here, get firstName, get lastName, get age.

[1:46] [1: 46] This syntax then is available pretty much whenever...You don't need to use keyof for this. You can use firstName, or lastName, or age here, and that will still work, but it gives you this ability to remap keys inside an object, which is of fascinating.