Quick Overview
A conditional type is a ternary the compiler evaluates, choosing one type when `T extends U` and another otherwise. `infer` captures part of the matched shape into a new variable, which is how `ReturnType` extracts a function's result.
Just as runtime code uses ternary conditionals (condition ? a : b), TypeScript supports Conditional Types in type space:
T extends U ? TrueType : FalseType
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
infer KeywordInside a conditional type's extends clause, the infer keyword declares a type variable that TypeScript will automatically extract and infer:
// Custom utility: Extract array element type
type ElementOf<T> = T extends (infer Element)[] ? Element : T;
type NumberItem = ElementOf<number[]>; // Inferred as: number
type StringItem = ElementOf<string>; // Inferred as: string
// Extract Promise resolved value type
type AwaitedType<T> = T extends Promise<infer Resolved> ? Resolved : T;
type AsyncData = AwaitedType<Promise<{ id: number }>>; // Inferred as: { id: number }
[ Input Type: Promise<string> ] ──> Matches Promise<infer Resolved>
│
▼
[ Extracted Type ] ──> Resolved = string
infer Outside Conditional Extends Clauses: The infer keyword CANNOT be used outside a conditional type's extends clause!Conditional types power modern state libraries and framework types. Next, let me explain Deep Readonly and Recursive Type Aliases!
TypeScript erases entirely at build time, so a `string` annotation produces no runtime check whatsoever. A value arriving from an API is whatever the server actually sent, regardless of what the annotation claims.
`let x = "GET"` infers `string` because the binding can change; `const x = "GET"` infers the literal `"GET"`. That widening rule is why object properties need `as const` to stay narrow.
`string[]` is any number of strings; `[string, number]` is exactly two, in that order. `readonly` removes the mutating methods at compile time, so `push` becomes a type error rather than a runtime surprise.