Ah, conditional types in TypeScript… They're like chameleons, changing shape and adapting to your code's needs! Maybe you’re already familiar with basic types, but conditional types take it to the next level. Think of them as smart types that adapt to situations—kind of like superheroes of typing. So, get comfortable and prepare to add some magic to your TypeScript code! 🧙♂️
Why Use Conditional Types? 🧐
In TypeScript, we love it when everything is neatly organized and strictly typed. But sometimes, our code needs a type that adapts based on certain conditions. Imagine you have a function that might return either a string
or a number
, depending on the input parameters. 😱 Without conditional types, you’d have to manually manage each case, and that quickly becomes tedious! Luckily, conditional types bring flexibility and responsiveness, like a typing ninja. 🥷
The Basics: Syntax of Conditional Types 🧩
Conditional types are somewhat like a ternary operator, but for types. Here’s an example to give you a taste:
In this example, IsString
is a conditional type that checks if T
is a string
. If it is, it returns "It's a string"
, otherwise "It's not a string"
. Simple enough, but wait until you see what we can do in more advanced cases!
Practical Example: Adapting a Type Based on Configuration 🛠️
Let’s imagine a function that takes a configuration parameter and must return a different type depending on that configuration. Conditional types are perfect for this kind of magic ✨!
Code Example
In this example, Response<T>
adapts the type based on whether mode
is "simple"
or "detailed"
. The magic happens: fetchData(simpleConfig)
returns an object with only data
, while fetchData(detailedConfig)
also includes details
. Convenient, right?
Nested Conditional Types: Typing à la Carte 🧇
Why stop there? You can also nest conditional types to handle even more precise cases! Imagine you want to adapt the type not only based on mode
but also on whether the user is authenticated or not. Ready for some advanced type juggling? 🎢
Here, UserResponse
adapts the type based on two criteria: mode
and isAuthenticated
. The result? Ultra-precise typing that covers all possible cases!
Advanced Conditional Types with infer
: Type Deduction 🕵️♂️
Ready for some advanced tricks? TypeScript has a special keyword for use in conditional types: infer
. It lets you infer a type directly within your conditional type. Handy for extracting information from complex types!
Example with infer
Here, ReturnTypeOfFunction
uses infer R
to deduce the return type of a function. In this example, HelloReturnType
will be of type string
because getHello
returns a string.
Conclusion 🎉
Conditional types in TypeScript are like superpowers for your code. They let you create dynamic types and maintain strict typing while making your code simpler. Ready to impress your colleagues? Experiment with these conditional types and discover new ways to structure your TypeScript code! 🚀
No more excuses for approximate types—with conditional types, your TypeScript code becomes virtually bulletproof! 👌
1type UserResponse<
2 T extends Config,
3 Authenticated extends boolean,
4> = Authenticated extends true
5 ? T['mode'] extends 'simple'
6 ? { data: string }
7 : { data: string; details: string[] }
8 : { error: 'Not authenticated' };
9
10function fetchUserData<T extends Config, Authenticated extends boolean>(
11 config: T,
12 isAuthenticated: Authenticated,
13): UserResponse<T, Authenticated> {
14 if (!isAuthenticated) {
15 return { error: 'Not authenticated' } as UserResponse<T, Authenticated>;
16 }
17 if (config.mode === 'simple') {
18 return { data: 'Simplified data' } as UserResponse<T, Authenticated>;
19 } else {
20 return {
21 data: 'Full data',
22 details: ['detail1', 'detail2'],
23 } as UserResponse<T, Authenticated>;
24 }
25}
26
27const resultAuthSimple = fetchUserData(simpleConfig, true); // { data: "Simplified data" }
28const resultAuthDetailed = fetchUserData(detailedConfig, true); // { data: "Full data", details: [...] }
29const resultNotAuth = fetchUserData(detailedConfig, false); // { error: "Not authenticated" }