Type Transformations Workshop (4 exercises)
solution

Create an Object using Mapped Types, Conditional Types, and TypeScript Keywords

Here's what my solution looks like:

As usual, we'll break it down bit by bit.

Turn the Discriminated Union into an Object

The first thing to do is turn the discriminated union into an object.

We can simplify this like so:

With the above, each of the members of the discriminated union is mapped into its own key:

Now that we have the keys we want, we need to find which ones include search.

We can't use an indexed access for this, because we know that they don't all have it:

Instead, we'll use extends to do a conditional check. If search is there, return it. Otherwise, return never.

There are a couple ways to do this.

One option is to add an object with a search key and an any type:

This works, and gets us what we need to make the test pass.

However, I prefer to use infer because it allows us to skip the indexed access:

It looks cleaner, and prevents other people who read the code from having to determine what the any is for.

Following this pattern to do checks is great in situations where you want to extract things that you aren't sure are present in all members of the union.

Transcript

[0:01] [0: 01] We know first of all that to take a discriminated union and turn it into object, it's pretty nice. We get to use this R in Route as R route, which we've seen before. If we just take this R now, and if we take R route's objects, we now have each of the members of this discriminated union mapped over into its own key. Very cool.
[0:22] [0: 23] That's good, because actually, what we want is to turn it into an object with those keys. This section is done for us. We don't need to think about that anymore. The tricky bit is this next section, because all we want from this routes object is actually to turn this, we want to basically grab the search out of it.

[0:42] [0: 43] We have our R here, and R can contain search or it might not contain search. We can't just do this, because R might not contain search at all times. R is going to be basically like one of these. Some of these contain search, some of them don't.

[1:01] [1: 01] You can't do a partial on this, or I can't do an index access on something that might not be there. We need to go in using a conditional type and grab it.

[1:12] [1: 13] What we're going to do is we could say R extends search any and then say R search, otherwise return never. That actually works and it works pretty well. You can see that it grabs all the pieces here, but I like doing it like this, which is to say infer S.

[1:30] [1: 30] Infer S in this position basically does the same thing except it does it without the index access check. It just says if this matches the search then grab it and then return it, which I think is just cleaner than looking at that and having to work out what that any is for.

[1:45] [1: 46] If that any is typed to something different, although unknown does work, undefined or something, then it's not going to work. I prefer using the infer S, because it just looks a little bit cleaner, and you get to understand exactly what this check is doing.

[2:02] [2: 03] Now this works, and this little check is so useful for being able to extract things that you're not sure are they in all members of the union.