Generic Defaults & Inference
Generic defaults give a type parameter a fallback ( ) when none is provided, while type inference lets TypeScript figure out a generic's type from the arguments you pass — so you rarely write the angle brackets yourself.
Learn Generic Defaults & Inference in our free TypeScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free TypeScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of a coffee order. Inference is the barista guessing your milk from what you usually get — you don't say it, they just know. A default is the house standard when you don't specify ("regular oat milk unless you say otherwise"). And a const type parameter is the barista writing down your exact order word-for-word ("extra-hot, half-shot") instead of rounding it to "a coffee" — the precise details are kept.
1. Default Type Parameters
You can give a generic a default with . If the caller neither supplies T nor gives the compiler something to infer it from, T falls back to that default. Defaults shine on generic interfaces and classes — like — so simple callers don't have to spell out a type argument.
2. How Inference Works (and When to Annotate)
Most of the time you never write — TypeScript infers the type argument from the value you pass. identity("hi") infers T = string ; first([true, false]) infers the element type. You must annotate only when there's nothing to infer from — for example a function that returns T[] but takes no T argument.
3. const Type Parameters & Widening
By default, inference widens literals: pass ["red", "green"] and you get string[] , losing the exact values. A const type parameter ( , TypeScript 5.0) tells the compiler to keep the narrowest literal type — the precise tuple — without scattering as const across every call.
🎯 Your Turn
Mirror a generic default using a default parameter : greet() with no argument should fall back to "guest" . Fill in the two blanks marked ___ , then run it.
No blanks this time — just a brief and a starting outline. Build the helper yourself, run it, and check your output against the example in the comments.
Practice quiz
What is a default type parameter?
- A runtime default argument
- An interface
- A fallback type for a generic, written like <T = string>
- A const assertion
Answer: A fallback type for a generic, written like <T = string>. <T = string> is the type-level version of a default function parameter.
When does the default in '<T = string>' get used?
- When the caller does not supply T and TypeScript cannot infer it from arguments
- Always
- Only with classes
- Only in strict mode
Answer: When the caller does not supply T and TypeScript cannot infer it from arguments. If T can be inferred from an argument, the inferred type wins; the default applies only otherwise.
How does TypeScript usually figure out a generic's type argument?
- You must always write <...>
- From the tsconfig
- Randomly
- It infers it from the values you pass at the call site
Answer: It infers it from the values you pass at the call site. identity("hi") infers T = string and identity(7) infers T = number, so you rarely write <...>.
When MUST you annotate a type argument yourself?
- Always
With no argument of type T, the compiler has nothing to read T from, so you write make<number>().
If you call 'function make<T>(): T[]' with no annotation, what is T?
- unknown
- string
- never
- any
Answer: unknown. With nothing to infer from and no default, T defaults to unknown.
By default, inference of '["red", "green"]' produces which type?
Inference widens literals, so you get string[] and lose the exact values.
What does a const type parameter '<const T>' (TS 5.0) do?
- Freezes the array at runtime
- Tells the compiler to infer the narrowest literal type instead of widening
- Makes T a constant value
- Requires 'as const' everywhere
Answer: Tells the compiler to infer the narrowest literal type instead of widening. <const T> keeps literal/tuple types, a cleaner alternative to scattering 'as const'.
Does '<const T>' change the runtime value of the array?
- Yes, it freezes it
- Yes, it copies it
- Only in development
- No — it only affects the inferred type
Answer: No — it only affects the inferred type. It changes only the type; the runtime array is exactly the same array.
Where must a defaulted type parameter appear relative to non-defaulted ones?
- Before them
- After them
- Anywhere
- Only alone
Answer: After them. <T = string, U> is invalid; defaulted type parameters must come after required ones.
On a generic interface, why add a default like 'ApiResponse<TData = unknown>'?
- For speed
- To enable inference of TData
- So simple callers can omit the type argument
- It is required syntax
Answer: So simple callers can omit the type argument. A default lets consumers write ApiResponse without spelling out the type argument.