infer Keyword and `ReturnType<T>`

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Professional TypeScript Masterclass Lessons

1.Introduction
free
⏱️ 1:54
2.Setup
free
⏱️ 5:44
3.Primitive Types
free
⏱️ 1:42
4.Instance Types
free
⏱️ 1:52
5.Arrays And Tuples
free
⏱️ 1:38
6.Objects
free
⏱️ 1:33
7.const declarations
free
⏱️ 1:03
8.Function Types
free
⏱️ 1:57
9.Structural Typing
free
⏱️ 2:10
10.Classes in TypeScript
free
⏱️ 1:48
11.Target Compiler Option
free
⏱️ 2:37
12.Generics
⏱️ 3:02
13.Special Types any And unknown
⏱️ 2:00
14.JavaScript to TypeScript
⏱️ 1:32
15.Frontend Projects
⏱️ 3:49
16.Type Assertions
⏱️ 2:15
17.Type Casting
⏱️ 1:16
18.Modules
⏱️ 1:55
19.Type Declarations
⏱️ 4:25
20.Creating NPM packages
⏱️ 3:20
21.Async Await
⏱️ 3:05
22.Running in NodeJS
⏱️ 1:40
23.Lexical this
⏱️ 2:34
24.readonly Modifier
⏱️ 1:59
25.Union Types
⏱️ 2:57
26.Literal Types
⏱️ 2:58
27.Type Narrowing
⏱️ 4:19
28.Discriminated Unions
⏱️ 3:29
29.Class Parameter Properties
⏱️ 1:02
30.Strict Compiler Option
⏱️ 6:18
31.null vs undefined
⏱️ 4:19
32.Intersection Types
⏱️ 2:03
33.Optional Modifier
⏱️ 2:47
34.Non Null Assertion Operator
⏱️ 3:40
35.Interfaces
⏱️ 2:28
36.Interface Declaration Merging
⏱️ 1:01
37.Types vs Interfaces
⏱️ 2:16
38.never Type
⏱️ 3:00
39.implements Keyword
⏱️ 1:25
40.Definite Assignment Assertion
⏱️ 2:31
41.User Defined Type Guards
⏱️ 2:02
42.Assertion Functions
⏱️ 3:42
43.Function Overloading
⏱️ 4:15
44.Call Signatures
⏱️ 2:53
45.Abstract Classes
⏱️ 1:53
46.Index Signatures
⏱️ 3:08
47.Readonly Arrays and Tuples
⏱️ 2:58
48.Double Assertions
⏱️ 2:20
49.const Assertions
⏱️ 3:55
50.this Parameter
⏱️ 2:33
51.Generic Constraints
⏱️ 2:43
52.typeof Type Operator
⏱️ 2:12
53.Lookup Types
⏱️ 3:12
54.keyof Type Operator
⏱️ 3:55
55.Conditional Types
⏱️ 4:39
56.Contitional Types with Unions and never
⏱️ 3:32
57.infer Keyword and `ReturnType<T>`
⏱️ 3:47
58.Mapped Types
⏱️ 2:48
59.Mapped Type Modifiers
⏱️ 3:37
60.Template Literal Type
⏱️ 4:28
61.Partial<T>
⏱️ 1:27
62.Required<T>
⏱️ 1:36
63.Readonly<T>
⏱️ 1:34
64.Record<K, T>
⏱️ 4:05
65.Project References
⏱️ 4:18
66.undefined vs. optional
⏱️ 2:48
67.satisfies Operator
⏱️ 2:42
68.PropertyKey Type
⏱️ 0:57
69.ThisType<T>
⏱️ 4:11
70.Awaited<T>
⏱️ 4:12
71.String Manipulation Types
⏱️ 3:36
72.Mapped Types as Clauses
⏱️ 4:01
73.Union vs Intersection Mental Model
⏱️ 3:36
74.Enums are Bad
⏱️ 8:11

infer Keyword and `ReturnType<T>`

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Basics

Infer is used to store a type in a variable e.g. the following stores the type of the array in Member:

type IsArray<T> =
T extends Array<infer Member>
? 'array'
: 'other';

Using the Inferred Type

We can use the inferred type in further conditions e.g.:

type UnboxArray<T> =
T extends Array<infer Member>
? Member
: T;

type UnboxedStringArray = UnboxArray<string[]>; // string
type UnboxedNumberArray = UnboxArray<number[]>; // number
type AnythingElse = UnboxArray<string>; // string

Use Case

For example we can create a powerful ReturnType<T> generic type function:

type ReturnType<T> =
T extends (...args: any) => infer R
? R
: never;

export function createPerson(firstName: string, lastName: string) {
return {
firstName,
lastName,
fullName: `${firstName} ${lastName}`
};
}

// Create the type
type Person = ReturnType<typeof createPerson>;

// Use the type
function logPerson(person: Person) {
console.log(
'Person:',
person.firstName,
person.lastName,
person.fullName
);
}

Further

The definition we have built for ReturnType<T> is actually built in to TypeScript so you don't need to create it yourself.

javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Here we have a conditional type that checks if the input generic extends in array, and if so, it returns the literal type array, otherwise it returns the literal type other. So if he inputs something that is an array, like a string array, we get back the little array. Otherwise, if he inputs something like a number, we get the literal other. Now, if we continue our mental model of thinking of conditional types as little type functions, the info keyword can be thought of as a way to create variables within the function. So the inputs of the type function are types

00:34

and the out outputs of the type function are types. Of course, the variables will also be types. For example, we can create a variable out of the type of the array using the infa keyword and giving that variable a name, for example, member. And now this variable member becomes available for access if the condition is true. Let's look at an example where we might want to create a variable within a conditional type. Here we have a type that can be used to unbox the members of an array. It checks if the input type extends an array, and if so, infers the members of the array.

01:08

And that is what is returned by the conditional type. Otherwise it simply returns whatever type was input into the condition. Let's look at a few examples where we use this type. If we input string array, it does extend an array and the member is inferred to be string, and that is what is returned. If we input a number array, the same thing happens. And in this case, the member number is returned for anything else, like just the string type, it returns it back as it is. Now let's add some JavaScript to look at a more practical use case

01:40

of using conditional types with the infer key word. Here we have a utility function that accepts two parameters, first name and last name, and then it returns an object containing three properties. First name, last name, and full name. We have another function in our code base that is designed to log a person and a person is anything that has been created from this create person utility function. Now of course at this point, we could create an explicit type to annotate what a person should be, but if you hover over the create person function, you can see that TypeScript already knows

02:13

what a person should be as the inferred return type of this function. So if we could infer the return type of this function, we wouldn't need to create the person type explicitly. So we create the conditional type return type that takes an argument of type T and checks. If T extends a function, if it does extend a function, we in further return value to BR and that is what we return. Otherwise, we assume that the programmer has probably made an error passing in something that is not extend a function and we return the special TypeScript type never.

02:47

And now that we have this utility return type, we can invoke it on the type of create person, the type of operator returns, the type inferred for the create person function. And then our return type utility Infers the return annotation. So if you hover over the person alias, you can see that it is exactly what we wanted and now we can use it to annotate our log person function. Now you might be thinking that that was a lot of work for very little gain. Well, the good news is that we don't need to create this return type ourself as it already ships as a part of the TypeScript compiler.

03:21

Similarly, we don't need to create a type alias. We can actually do it just in line. And now if you ever end up in a situation where the input of one function depends upon the output of another function, you can actually generate the type on the fly. And if the output of the first function error changes, you get a nice compiler error from TypeScript and you can go ahead and fix that.

Professional TypeScript Masterclass

Professional TypeScript Masterclass

1.Introduction
free
⏱️ 1:54
2.Setup
free
⏱️ 5:44
3.Primitive Types
free
⏱️ 1:42
4.Instance Types
free
⏱️ 1:52
5.Arrays And Tuples
free
⏱️ 1:38
6.Objects
free
⏱️ 1:33
7.const declarations
free
⏱️ 1:03
8.Function Types
free
⏱️ 1:57
9.Structural Typing
free
⏱️ 2:10
10.Classes in TypeScript
free
⏱️ 1:48
11.Target Compiler Option
free
⏱️ 2:37
12.Generics
⏱️ 3:02
13.Special Types any And unknown
⏱️ 2:00
14.JavaScript to TypeScript
⏱️ 1:32
15.Frontend Projects
⏱️ 3:49
16.Type Assertions
⏱️ 2:15
17.Type Casting
⏱️ 1:16
18.Modules
⏱️ 1:55
19.Type Declarations
⏱️ 4:25
20.Creating NPM packages
⏱️ 3:20
21.Async Await
⏱️ 3:05
22.Running in NodeJS
⏱️ 1:40
23.Lexical this
⏱️ 2:34
24.readonly Modifier
⏱️ 1:59
25.Union Types
⏱️ 2:57
26.Literal Types
⏱️ 2:58
27.Type Narrowing
⏱️ 4:19
28.Discriminated Unions
⏱️ 3:29
29.Class Parameter Properties
⏱️ 1:02
30.Strict Compiler Option
⏱️ 6:18
31.null vs undefined
⏱️ 4:19
32.Intersection Types
⏱️ 2:03
33.Optional Modifier
⏱️ 2:47
34.Non Null Assertion Operator
⏱️ 3:40
35.Interfaces
⏱️ 2:28
36.Interface Declaration Merging
⏱️ 1:01
37.Types vs Interfaces
⏱️ 2:16
38.never Type
⏱️ 3:00
39.implements Keyword
⏱️ 1:25
40.Definite Assignment Assertion
⏱️ 2:31
41.User Defined Type Guards
⏱️ 2:02
42.Assertion Functions
⏱️ 3:42
43.Function Overloading
⏱️ 4:15
44.Call Signatures
⏱️ 2:53
45.Abstract Classes
⏱️ 1:53
46.Index Signatures
⏱️ 3:08
47.Readonly Arrays and Tuples
⏱️ 2:58
48.Double Assertions
⏱️ 2:20
49.const Assertions
⏱️ 3:55
50.this Parameter
⏱️ 2:33
51.Generic Constraints
⏱️ 2:43
52.typeof Type Operator
⏱️ 2:12
53.Lookup Types
⏱️ 3:12
54.keyof Type Operator
⏱️ 3:55
55.Conditional Types
⏱️ 4:39
56.Contitional Types with Unions and never
⏱️ 3:32
57.infer Keyword and `ReturnType<T>`
⏱️ 3:47
58.Mapped Types
⏱️ 2:48
59.Mapped Type Modifiers
⏱️ 3:37
60.Template Literal Type
⏱️ 4:28
61.Partial<T>
⏱️ 1:27
62.Required<T>
⏱️ 1:36
63.Readonly<T>
⏱️ 1:34
64.Record<K, T>
⏱️ 4:05
65.Project References
⏱️ 4:18
66.undefined vs. optional
⏱️ 2:48
67.satisfies Operator
⏱️ 2:42
68.PropertyKey Type
⏱️ 0:57
69.ThisType<T>
⏱️ 4:11
70.Awaited<T>
⏱️ 4:12
71.String Manipulation Types
⏱️ 3:36
72.Mapped Types as Clauses
⏱️ 4:01
73.Union vs Intersection Mental Model
⏱️ 3:36
74.Enums are Bad
⏱️ 8:11