Type Transformations Workshop (9 exercises)
solution

Create Functions that Return Types

The solution to our ReturnWhatIPassIn type helper has some syntax we haven't seen yet:

The angle brackets next to ReturnWhatIPassIn kind of create a variable called T, which is then returned.

Note that we could call T whatever we want, and the type helper would still work as expected:

For example, if we call our type helper like this:

The type Something will equal whatever we pass in to ReturnWhatIPassIn.

Expanding our Type Helper

We could update ReturnWhatIPassIn to return either the same thing that was passed in or undefined:

Now if we update our Something example to pass the number 12 into ReturnWhatIPassIn:

Hovering over it in VS Code shows us that our type is either 12 or undefined:

Recapping the Type Helper Pattern

This type helper pattern allows us to create functions which can return other types.

With this syntax, ReturnWhatIPassIn is now a function, <T> is the argument to the function, and T is what it returns:

If we remove the <T>, then ReturnWhatIPassIn becomes a static value:

We can also add as many arguments as we want, and use other features like default values and constraints.

Introducing Generics

This syntax and pattern is our first look at generics on the type level. However, since that term is widely used I'm going to refer to these types of functions as type helpers.

The concept here is the basis for what a lot of what TypeScript is built on.

For example, if we create a Record type:

We can use VS Code to navigate to the source of Record and see that it follows this pattern:

We'll be going much deeper into generics throughout Total TypeScript.

For now, the takeaway is that type helpers allow you to pass in arguments and return things from that function.

Transcript

[0:01] There's a lot of new syntax here, so let's examine what's going on. We have a type helper which is ReturnWhatIPassIn. This has now a couple of little angled brackets here, and it creates this variable called T. I can call this whatever I want. I can call it TWhatever, and it will still work the same way.
[0:23] What happens is, now when I have type Something = ReturnWhatIPassIn<something>, this is going to equal whatever I pass in. We can really, really run with this. Imagine if we have 12 here, for instance. I could do this or undefined, for instance. Now it would be 12 or undefined.

[0:47] What this allows us to do is create functions which can return other types. This is a function now. This is the argument to the function, and this is what the function returns. If we were to remove this, then it would no longer be a function. It would be a static value. This is just 12 here.

[1:07] Whereas, if I declare it with this, then we can do really, really crazy stuff with this. We can start creating these functions which return other types. I can add as many of these as I want to here -- TWhatever2, TWhatever3. I can keep going and going and going. I can give them default values. I can make them constrained to certain things. That's what we're going to learn about in this section here.

[1:35] This whole idea of type functions, this is a lot about what we call generics on the type level. You might have heard of generics before, and I've got an entire module talking about generics. Generics is a pretty widely used term. I'm going to refer to these mostly as type helpers because that's sort of what they are. We have a function that returns another type.

[2:00] Generics in functions, generics in classes, they do slightly different things, but use similar syntaxes. I wanted to introduce this first because this is like the basis for what a lot of TypeScript is built on. If we look at, for instance, the record time, so if I say Yeah = Record, and I'll put any, any in here now, and if we command-click to this, then you can see this uses the same sort of pattern.

[2:25] If we ignore this extends for now, then what we get is type record equals this, so it's a function with two arguments, K and T, and it returns something here. That's the whole idea about these type helpers. You can pass in arguments and return things from that function.