When does TypeScript infer generic type arguments, and when must you pass them yourself?
TypeScript infers type arguments from the values you pass. You must write them explicitly when no argument carries the type, such as an empty collection or a function whose type appears only in the return, or when you want a wider type than the inferred one.
Explain it simply
When you give a courier a parcel, he reads the label and knows where it goes. Generics work like that: pass "Asha" and the compiler decides T is string.
But if you send an empty box, there is no label. new Set() alone has nothing to read from, so you tell it: new Set<number>(). The same happens with functions like getJson<T>() whose type appears only in the return position.
Example
function identity<T>(x: T): T { return x; }
const a = identity("hi"); // T inferred as "hi" -> a: "hi"
const b = identity<string>("hi"); // T forced to string -> b: string
const empty = new Set(); // Set<unknown>
const ids = new Set<number>(); // explicit
ids.add(7);
async function getJson<T>(url: string): Promise<T> {
const res = await fetch(url);
return res.json() as Promise<T>; // T cannot be inferred from url
}
// const user = await getJson<{ name: string }>("/api/user");
const list = [] as string[]; // another way to type an empty arrayWhat to say in the interview
"Inference works from arguments. When nothing in the call carries the type, like an empty collection or a return-only type parameter, or when I want a wider type than the literal inferred, I pass the type argument in angle brackets. For a fetch helper that is a promise to the compiler, not a check."
Common mistakes
- Believing getJson<User>() validates the response; it only asserts the type.