Skip to main content

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.