Module 18: Conditional Types
Conditional types enable type-level if-else logic, allowing you to create types that adapt based on conditions.
1. Basic Conditional Types
type IsString<T> = T extends string ? true : false;
type T1 = IsString<string>; // true
type T2 = IsString<number>; // false
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
"other";
2. Conditional Types with Generics
type NonNullable<T> = T extends null | undefined ? never : T;
type T0 = NonNullable<string | null>; // string
type T1 = NonNullable<number | undefined>; // number
3. Inferring Types
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { name: "Alice", age: 25 };
}
type User = ReturnType<typeof getUser>; // { name: string; age: number; }
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type Result = UnwrapPromise<Promise<string>>; // string
4. Distributive Conditional Types
type ToArray<T> = T extends any ? T[] : never;
type T1 = ToArray<string | number>; // string[] | number[]
type NonDistributive<T> = [T] extends [any] ? T[] : never;
type T2 = NonDistributive<string | number>; // (string | number)[]
5. Advanced Inference Patterns
type FunctionReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type FunctionParameters<T> = T extends (...args: infer P) => any ? P : never;
type ConstructorParams<T> = T extends new (...args: infer P) => any ? P : never;
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never;
6. Conditional Type Chains
type Flatten<T> =
T extends Array<infer U> ? Flatten<U> :
T extends Promise<infer U> ? Flatten<U> :
T;
type T1 = Flatten<Promise<string[]>>; // string
type T2 = Flatten<Array<Array<number>>>; // number
7. Type Guards with Conditional Types
type IsArray<T> = T extends any[] ? true : false;
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
type IsObject<T> = T extends object ? (T extends any[] ? false : true) : false;
8. Real-World Example: API Response Type
type APIResponse<T> =
T extends { error: any }
? { success: false; error: string }
: { success: true; data: T };
interface UserData {
name: string;
email: string;
}
interface ErrorData {
error: string;
}
type UserResponse = APIResponse<UserData>;
// { success: true; data: UserData; }
type FailedResponse = APIResponse<ErrorData>;
// { success: false; error: string; }
Key Takeaways
✅ Conditional types create type-level logic
✅ infer keyword extracts types
✅ Distributive behavior over unions
✅ Chain conditions for complex transformations
✅ Essential for advanced generic patterns
Practice Exercises
Exercise 1: Deep Extract
type DeepExtract<T, U> = T extends U ? T :
T extends object ? { [K in keyof T]: DeepExtract<T[K], U> }[keyof T] :
never;
Exercise 2: Function Overload Types
Create conditional types for function overload resolution.
Next Steps
In Module 19, we'll explore Template Literal Types for string manipulation at the type level.