TypeScript Advanced: The Type System
Conditional and Mapped Types
In this lesson you will
- Write a conditional type with extends and infer
- Transform object types with a mapped type
- Add, remove and rename properties with modifiers and key remapping
Introduction
At this level, types are no longer just labels. They are a small programming language that runs inside the compiler: types can take inputs, make decisions and produce new types. This is how libraries compute precise types for you, and how the utility types such as Partial and ReturnType are built.
Types cannot be printed, so the examples below check a type by assigning a value to it. If the value does not fit, the compiler reports an error, and that error is your "output". Read the Type check panel after each run.
Conditional types
A conditional type looks like a ternary: T extends U ? X : Y. Read it as "if T is assignable to U, then X, otherwise Y".
A practical use is to compute a return type from an input type:
T[number] means "the type of the items in the array T".
Quick quiz
How do you read T extends string ? true : false?
Extracting with infer
Inside a conditional type, infer R captures a part of the matched type, giving it a name you can use. This is exactly how ReturnType works:
Read the condition as: "if F is a function, call whatever it returns R and give me R".
Another useful one pulls the value out of a promise:
Distributive conditional types
When you give a conditional type a union, it is applied to each member separately and the results are joined.
ToArray<string | number> is string[] | number[], not (string | number)[]. This is how Exclude removes members from a union.
Mapped types
A mapped type builds an object type by looping over keys. The syntax is { [K in Keys]: Type }, where keyof T is the union of T's property names.
Every property of Features is kept, but its value type becomes boolean. This is how Partial works. Here it is rebuilt by hand, together with the modifiers ? and readonly:
A leading - removes a modifier and + adds it.
Quick quiz
What does { [K in keyof T]: boolean } produce?
Key remapping
With as you can rename keys while mapping, and even drop some by mapping them to never.
The backtick part is a template literal type, which the next lesson explains. For now, notice that name became getName and age became getAge.
Filtering keys by their value type:
Try it yourself
Write a mapped type Nullable<T> that makes every property of T accept null as well as its normal type. The stub does not do that yet, so the last line fails. Fix it so that the program compiles.
Summary
- Conditional types choose a type:
T extends U ? X : Y.infercaptures a part of the matched type. - Over a union, a conditional type is applied to each member separately.
- Mapped types loop over keys:
{ [K in keyof T]: ... }. You can add or remove?andreadonly. asin a mapped type renames or filters keys.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading