The Utils Folder 10 exercises
solution

Asserting Types with Type Predicates

The solution is to add a type annotation onto the return type of assertIsAdminUser.

If it was a type predicate, we would say user is AdminUser:


function assertIsAdminUser(user: User): user is AdminUser { // red squiggly line under user is AdminUser
if (!("roles" in user)) {
throw

Loading solution

Transcript

00:00 The solution here is to add a type annotation onto the return type of assertIsAdminUser. If this was a type predicate, we would say userIsAdminUser just here, so userIsAdminUser. But there's an issue here. If we take a look, a function who's declared type is

00:18 neither undefined void nor any must return a value. The issue is that we're not actually returning anything from assertIsAdminUser, we're returning void here. So it's actually slightly different because a type predicate requires that you return a Boolean, whereas assertIsAdminUser is actually returning nothing.

00:37 So instead we can say assertUserIsAdminUser. Look at that, assertIsUserIsAdminUser. And now what this is saying is that when this function is called, it asserts just by the very fact that it was run that this user is an admin user. We don't need to put it inside an if statement, we don't need to put it anywhere really.

00:56 We can just literally assert it. And if I comment this out, you notice that inside handleRequest, when I comment it out, user then becomes user or admin user. When I uncomment it, we get it's just an admin user. Because if we hover over assertIsAdminUser, it asserts userIsAdminUser. Are you sick of the word user yet?

01:15 I certainly am. This is really cool because it means that we can capture reusable validation logic inside functions that can just be called, that don't need to be put inside if statements. And it's almost like we get to really just add a bit of try-catch logic into a reusable function.

01:34 Now, this very similar to type predicates is not perfectly type safe. We could say assertsUserIsUser here. And now we're actually doing the reverse of what our code actually says. So you need to make sure that TypeScript sort of, because TypeScript isn't gonna keep these two pieces in sync,

01:51 the runtime code and the type annotation here. So you need to make very sure that what you're asserting actually matches up to your return type. But if you do that, then you do get a really, really powerful paradigm that lets you be really expressive with the way your functions work.