Skip to main content

Type inference with generics

What type inference means for generics

When you call a function with a generic parameter, TypeScript analyzes the arguments you pass and substitutes the type itself in place of T (or other parameters). In other words, you do not need to explicitly write <string>, <number>, and so on - the compiler does it automatically.

Example 1: basic type inference

javascript
function identity<T>(value: T): T { return value; } const a = identity("Hello"); // T = string const b = identity(42); // T = number

TypeScript sees that the argument "Hello" has type string, and substitutes T = string automatically.

Example 2: inferring a type from several arguments

javascript
function merge<T, U>(a: T, b: U): T & U { return Object.assign({}, a, b); } const result = merge({ name: "Tim" }, { age: 25 }); // TypeScript infers T = { name: string }, U = { age: number } // The result has type { name: string; age: number }

Here T and U are inferred from each argument separately. TypeScript combines them with &.

Example 3: inference from context (contextual inference)

javascript
function wrap<T>(value: T): { data: T } { return { data: value }; } const wrapped = wrap({ id: 1, name: "Tim" }); // T = { id: number; name: string }

TypeScript "sees" the structure of the passed object and infers the exact type.

Example 4: partial inference

javascript
function pair<T, U = string>(first: T, second?: U): [T, U] { return [first, second as U]; } const p1 = pair(1); // T = number, U = string (default) const p2 = pair(true, false); // T = boolean, U = boolean

You can set a default type for a generic parameter - it is then used when TypeScript cannot infer the type from the arguments.

Example 5: inferring the type from a function's return value

javascript
function makeArray<T>(item: T, times: number): T[] { return Array(times).fill(item); } const arr = makeArray(5, 3); // T = number → number[]

The type T is inferred from the first argument, item.

Example 6: when inference does not work

javascript
function logValue<T>(value: T): void { console.log(value); } logValue(null); // T cannot be inferred precisely logValue(undefined); // same here

In such cases you need to specify the type explicitly:

javascript
logValue<string | null>(null);

How inference works under the hood

TypeScript applies several strategies:

  1. From arguments → to type parameters - analyzing the arguments and their types.
  2. From return type - if the result type can be computed.
  3. Contextual typing - analyzing the context where the function is used.

Example of contextual inference:

javascript
const handler = <T>(value: T) => console.log(value); ["a", "b", "c"].forEach(handler); // TypeScript understands that T = string

Summary

What TS doesExampleResult
Infers a type from an argumentidentity(42)T = number
Infers a type from several argumentsmerge({a: 1}, {b: 2})T = {a: number}, U = {b: number}
Applies a default typepair(1)U = string
Contextual inference["x"].forEach(handler)T = string
Cannot infer the typelogValue(null)must be specified explicitly

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.