Skip to main content

Type inference with generics

What type inference means in the context of generics

When you call a function with a generic parameter, TypeScript analyzes the arguments passed and substitutes the type itself for T (or other parameters). That is, you don't need to explicitly write <string>, <number>, and so on - the compiler does this 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: inference from multiple 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 separately for each argument. TypeScript combines them via &.


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: type inference on 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); // the same applies

In such cases the type must be specified 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 - when the result type can be computed.
  3. Contextual typing - analyzing the context in which the function is used.

An 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 the type from an argumentidentity(42)T = number
Infers the type from multiple argumentsmerge({a: 1}, {b: 2})T = {a: number}, U = {b: number}
Applies the 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.