Conditional Types

Intro to Conditional Types
Conditional types are like if statements for types. They let you choose between types based on conditions.
type IsString<T> = T extends string ? true : false

type A = IsString<string> // true
type B = IsString<number> // false

The Syntax

T extends U ? TrueType : FalseType
  • If T is assignable to U, the result is TrueType
  • Otherwise, the result is FalseType

Practical Examples

// Extract return type of a function
type Return<T> = T extends (...args: Array<any>) => infer R ? R : never

// Unwrap a Promise
type Unwrap<T> = T extends Promise<infer U> ? U : T

// Filter union types
type OnlyStrings<T> = T extends string ? T : never
type Result = OnlyStrings<'a' | 1 | 'b' | 2> // 'a' | 'b'

// Check if a type has a specific property
type Ticket = { priority: 'low' | 'high'; id: string }

// Check if a type has a specific property
type IsHighPriority<T> = T extends { priority: 'high' } ? true : false

// Extract the type of a specific property
type High = IsHighPriority<Ticket> // false (priority is not a single literal)
// Extract the type of a specific property
type HighOnly = IsHighPriority<{ priority: 'high' }> // true

The infer Keyword

infer declares a type variable within the condition:
type GetArrayElement<T> = T extends Array<infer E> ? E : never

type Element = GetArrayElement<Array<string>> // string
Conditional types are advanced but essential for understanding how TypeScript's utility types work, especially ReturnType, Parameters, and Awaited.
In this exercise, you'll create conditional type utilities.