Conditional Types and Infer 10 exercises

Infer Elements Inside a Conditional with Infer

This challenge has two solutions.

Solution 1

The first solution might look pretty similar to pieces that you've kind of understood before:

type GetDataValue<T> = T extends { data: any } ? T["data"] : never;

First we use extends to see if T has an object with a data attribute

Loading solution


0:00 This problem has multiple solutions. The first solution might look pretty similar to pieces that you've understood before. We're first checking if T extends data any here. If it does, then we know that T has a data attribute on it, and so we can just return that data attribute. Otherwise, we return never.

0:20 This, we're using an index access type, which we've already seen. This is pretty cool. The one I wanted to point your attention to though is this infer here. What's going on here instead, now what we're saying is T extends data infer TData. Instead of this any, we've now got this infer attribute in the middle, which is saying whatever is passed in here, then just infer its type.

0:50 What this does is it declares a TData just for the positive condition. This means we can't access TData here because it says cannot find name TData. That variable isn't defined in that branch. It's only defined in this branch here. This is a way of adding another variable into the function.

1:12 We can say, if we had TData up the top here, then this is kind of the same thing, except it would be declared in the whole scope. What infer does is it allows you, inside the scope of a conditional check, to pattern-match against the thing you're checking and extract out a new type variable.

1:31 What this means is that TData now, we've extracted it, and it could be anything that's inside this TData or inside this data slot. We just then return it. If we say type Example = GetDataValue -- let's say we have a data, and let's say it's just a 1 here -- this is going to extract the 1. We could even do TData or undefined here, and we end up with 1 or undefined.

1:57 When you're choosing these two possibilities, which one should you pick? I tend to prefer the second solution because this infer TData gives me a new opportunity to name a variable. We could even call this TInferredData or something here. For me, this reads pretty nicely in terms of the syntax here.

2:21 With this one, we're saying data.

2:23 any and then extracting it there. Whereas here, all of the logic is expressed inside the conditional check. This infer, it's really, really powerful. I suggest that the next time you're inside a conditional check, and you need to extract out something interesting, you use infer because it is extremely powerful.