Entry / Feb 27, 2026
TypeScript infer and Conditional Types: From Junior to Senior in 11 Minutes
Why conditional types and `infer` help TypeScript extract hidden information, model safer APIs, and replace brittle type shortcuts with better design.
👉 Watch on YouTube
Most developers use TypeScript as if it were only a layer of annotations.
Add a few interfaces. Type a few function arguments. Fix a compiler error. Move on.
But this video makes a more interesting point: TypeScript is not just a static checklist for your code. It is a type system that can inspect, transform, and derive information from other types.
That is where conditional types and infer start to matter.
TypeScript can do more than describe values
The core idea in the video is simple.
You do not always need to write the final type by hand.
Sometimes the type you want is already hiding inside another type, and TypeScript can extract it for you.
That is exactly what conditional types are for.
type Result<T> = T extends string ? "text" : "other";
This looks like an if statement, but for types.
If T matches one shape, TypeScript returns one branch. If
it does not, it returns the other.
That sounds small, but it changes how you design APIs.
Why conditional types matter in real code
Without conditional types, many APIs become overloaded, repetitive, or full of weak type assertions.
That usually leads to code that:
- repeats the same intent in several places
- loses precision as more cases are added
- falls back to
anyoraswhen things get messy - becomes harder for autocomplete to understand
Conditional types let you encode the relationship between an input type and an output type directly.
That is more than convenience.
It is a way to move the contract into the type system instead of leaving it in the developer’s head.
infer extracts the part you actually need
The real jump in the video happens when infer enters the
picture.
infer lets TypeScript introduce a temporary type variable
while matching a structure.
For example, if you want the element type inside an array, you can write this:
type ElementOf<T> = T extends Array<infer Item> ? Item : T;
type A = ElementOf<string[]>; // string
type B = ElementOf<number>; // number
This is one of the clearest reasons infer feels powerful.
You are no longer manually indexing into a type and hoping you modeled every case correctly. You are telling TypeScript to look at the shape and pull out the missing piece.
That makes utility types easier to read and easier to reuse.
The factory example is where the design payoff shows up
One of the most useful ideas from the video is the state/factory-style example.
The function receives some input that identifies a variant, and the return type should match that exact variant.
This matters because many codebases start with a broad union and end up returning something too generic.
Then the caller has to narrow everything again.
With conditional types, you can model that relationship so a function returns the specific shape associated with the input type.
That gives you:
- more accurate autocomplete
- fewer manual assertions
- cleaner factories and helpers
- APIs that preserve intent instead of erasing it
This is where TypeScript stops feeling decorative.
It starts helping you model behavior.
infer is not magic in isolation
It only works inside a conditional type, and it works best when you already understand the structure you are matching.
That is why the video’s progression makes sense:
- understand
T extends X ? Y : Z - identify the hidden part of the type you want
- use
inferto capture that part - reuse the result in a cleaner contract
Once you see it that way, infer stops looking mysterious.
It becomes pattern matching for types.
A practical expansion: arrays, promises, and functions
The video focuses on array-like and factory-style examples, but the same idea shows up everywhere in modern TypeScript.
For promises:
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type Data = UnwrapPromise<Promise<{ id: string }>>;
// { id: string }
For functions:
type GetReturn<T> = T extends (...args: never[]) => infer R
? R
: never;
type Output = GetReturn<() => { ok: true }>;
// { ok: true }
These are not obscure tricks. They are the same idea behind
built-in helpers like ReturnType and Awaited.
That is important because it shows infer is not a novelty.
It is part of how TypeScript itself models common patterns.
Distributive conditional types are where things get sharp
One concept worth expanding beyond the video is distribution over unions.
When a conditional type receives a union, TypeScript often applies the condition to each member separately.
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>;
// string[] | number[]
That behavior is often useful, but it can also surprise you.
It is one of the reasons advanced utility types sometimes feel harder than they first appear. The syntax is small, but the consequences can be large.
So if infer ever feels inconsistent, the missing concept
is often distributive conditional types.
When infer is the right tool
infer works especially well when:
- a type already contains the information you need
- you want to keep one source of truth
- a helper should adapt to several related shapes
- the alternative would be overload bloat or repetitive manual typing
This is great for arrays, promises, function signatures, event payloads, discriminated unions, and reusable library helpers.
When not to use it
Not every type problem needs infer.
Sometimes a plain generic is clearer.
Sometimes an explicit union is more honest.
Sometimes an overload communicates intent better than a dense type-level puzzle.
That is the real maturity test.
Senior TypeScript is not about writing the most clever type.
It is about choosing the most readable contract that still protects the code.
If infer removes duplication and preserves meaning, it is
doing its job. If it makes a simple API unreadable, it is
probably the wrong abstraction.
The takeaway
The biggest lesson from this video is not that infer is
powerful.
It is that TypeScript can derive more than most developers ask from it.
Conditional types let you express relationships.
infer lets you extract the missing piece from those
relationships.
Together, they help you build code that is:
- more precise
- easier to reuse
- safer to evolve
- less dependent on
anyand unsafe assertions
That is what makes the jump from basic typing to real type design.
