Type Helpers 9 exercises

Use Constraints to Limit Type Parameters

The solution is to update AddRoutePrefix so we can only pass in a string.

To do this, we'll add extends string to the type helper to tell it that TRoute must be a string:

type AddRoutePrefix<TRoute extends string> = `/${TRoute}`;

More on Constraints

As seen in the introducti

Loading solution


0:00 The way you fix this error then is we somehow need to make TRoute here, we need to make sure that the only thing you can pass it is a string, and the way you do that is you say TRoute extends string. 0:14 OK. What's the syntax doing here? It's basically saying that TRoute must be a string, and if we try to pass in a Boolean here, then it's going to say type Boolean does not satisfy the constraint string.

0:28 If you mention that this was just a normal function, we say const addRoutePrefix as a function, and we've got our route inside here, then basically, this is the same thing as we're doing here. If we say root: string, we're doing exactly the same thing as addRoutePrefix is doing.

0:48 This is a way of giving a parameter or giving a type to the type parameter that is being passed in. The cool thing about TypeScript is you don't need to do this. Because this is all happening on the Type-Level, it has perfect information so it will infer it based on what you pass in.

1:06 But if you want to do things with it that are required for a string to be able to do, like being a part of another template string, then you need to constrain it properly. We could constrain this to be a number if we want, and this wouldn't complain because you can pass numbers to a template literal, which is pretty cool.

1:25 Yeah, that's the basic idea of this. We can do lots of things with this. We can actually mimic the type that it's complaining about here if we wanted to. If we copy this over, we go string or number or bigints, and we can pass that directly into there and that won't moan.

1:42 For instance, if we add another member to this like wow: 1, then now, it's going to moan because wow: 1 is not assignable to that type, but you get the idea. We can basically now guarantee that TRoutes extends a certain type.

1:54 If you don't do that, if you don't pass in a type into here, a type constraint, then it's going to assume the TRoute is unknown. That's the type that it defaults to. We know that in TypeScript, unknown, so routes., it doesn't really have any properties associated. We really don't know what it is.

2:14 It's like one step above any, in times of danger, but at least we know what the danger is. That's a good way of thinking about it. If you don't specify this, then anything you do with that TRoute is going to be unknown.

2:27 If you do specify constraints, then that means that you can get a sense of what's happening to this, and often, other type helpers will specify their own constraints too. If we say type Yeah = Record<string, string>, then if we look inside Record, command click here, we can see that it extends keyof any.

2:48 We'll get to what that means later, but you get the sense that, OK, I can add these different constraints onto my type helpers to make sure that my users can only pass certain things in.