Type Transformations Workshop (4 exercises)
solution

Extract from String with Mapped Types, Template Literals, and infer.

Here's the solution I found to this challenge:

Let's break it down.

First, we have ExtractPathParams that takes in <TPath extends string>.

This says that we are only able to pass in strings. Anything else, and TypeScript will yell at us. We'll look more at this syntax in a future workshop, but you get the idea for now.

Next, we have a mapped type.

The syntax in the solution is a little bit messy, so here's a simplified version:

As we've seen before, this would split a path on the / character, and turn each part into a key with a string:

Now let's look at it the context of the full solution again:

Look at the K extends :${infer P} part. If this passes we know that there's a colon at the start so we know our path has a dynamic parameter.

From there, infer will return the part that was extracted. This is a really cool use of infer!

If there is no match, then never is returned.

There are many possible solutions to this problem, but hopefully this one gives you a sense of whether or not yours was correct.

Either way, this hopefully gives you an idea about how you might tackle this sort of problem in the future!

Transcript

[0:00] This is the solution I found to this challenge. Let's break it down. First of all, we've got this ExtractPathParams type helper here, and we're taking in a parameter which is called Tpath. I'm going to start deleting this, and you're going to see that it starts breaking.
[0:17] Let's just say type Result = ExtractPathParams, and let's say UserOrganizationPath, since that's the more complicated one. We can see that we end up with id and organizationId. Let's have a look at this extends string syntax first.

[0:30] What happens if I delete that? Well, it looks like we've got an S.Split down here, which we saw earlier. This is saying this type parameter might need an extend string condition.

[0:43] What this is doing is it's saying that we can only parse strings into our ExtractPathParams helper, so if we parse in a number here, then it's actually going to yell at us. We're going to cover this more in a future module, but you get the idea.

[0:55] Now what we're doing is this very messy syntax here, if I clean this up a little bit, you can see that we're doing a map type here. Now the result, it looks like if I remove this, it looks like there's a K in something, and then there's an as here.

[1:12] If I remove the as and the second little conditional here, then we actually end up with all of the members of this thing split up here. We've got an empty thing here, then users, then id, organizations, then organizationId.

[1:29] It looks like what's going on is we're splitting up the path and then taking all of the members of the path and then turning those into the keys. If I add this back in, let's break that down a little bit further.

[1:42] If we say type Result2 equals this, and let's say, UserOrganizationPath, now what we get here, these are all of the members of this. If we remove the number too, it splits into an array, and by adding number on the end, we end up with all of the members of that array expressed as a union.

[2:04] Now that we've got that, that's what K represents. K represents Result2 here. What we're then saying is we're remapping that to if K extends, infer P while we return P.

[2:20] If it has a colon at the start, then we know that that's going to be a dynamic parameter, so it's going to be either id or organizationId, and we infer the rest of it during that check. Woah. Amazing use case for infer.

[2:36] If we find it, if it matches one of these, then we return the parameter that we extracted, otherwise we return never. If we were to return wow inside here, then we'd always end up with this other parameter wow. Never basically says if it doesn't match this dynamic thing, then exclude it.

[2:55] All of the values return a string, because that's how path parameters work basically. That's pretty amazing, and if we test this with UserPath instead, then we end up with just id string.

[3:08] There are many, many different solutions to this possible problem, but hopefully, this one gives you a sense of how you could clean yours up or whether yours was correct. To be honest, if yours is working, then great job. This is a very, very difficult problem, and you managed to find a decent solution.

[3:25] If you didn't manage to find a solution, then hopefully, this one gives you an idea about how you might tackle this in the future.