Intro to Generics 9 exercises
solution

Add Object Property Constraints to a Generic

Let's take this solution step-by-step.

Add the Generic

The first thing to do is add the generic, which in this case will be TUser:

export const concatenateFirstNameAndLastName<TUser>(user: TUser) => {
  return {
    ...user,
    fullName: `${user.firstName} ${user.lastName}`,
Loading solution

Transcript

0:00 The solution to start with for any generic function is to add the generic. I'm going to call this T user. Now, we're going to pass in T user to here. This starts to make a bit of sense. We start getting some good stuff here. We can see the new users now, our ID number, first name, last name, and full name here.

0:22 This means that if we grab this new user, constant new user equals new users, the first one, then what we're going to see here is we have our fully decked-out object. All of the right properties are being put in. Except we're getting an error here because property first name does not exist on type T user.

0:43 Just like when you use a type helper, this is going to default to unknown. In other words, it doesn't actually know what type this is going to be. We need to constrain it to say that it has to extend first name string and last name string.

1:02 Whatever T user is, it is an object that has these properties with this and this. This means that we can basically autocomplete our way there to inside the function, which is really nice. Also, it means that if we try to pass in anything that doesn't have all the right stuff, then it's going to yell at us because last name is missing in "Type first name" here.

1:22 This brings together a few things that we've seen so far. We've got a extends clause giving a constraint to this. We're doing a really nice job with T user making sure this is in the right place. Also, this is really nice, too, that we actually don't need to declare the return type here.

1:39 We could do if we want to. We could say we're returning T user. We're adding a property to it. We're adding full name string here, which is really, really nice. You might also want to say we're emitting full name from the user, which is a thing that we're doing. It's not declared in the types by default.

2:03 What you get then is you don't actually need to declare this. We hover over this. We look at it, T user and full name string. If we remove this...and TypeScript actually infers this itself, really, really clever.