Syntax
function name<T>(param: T): T { }Examples
A Generic Function
A function that works with any type, while TypeScript still tracks exactly which type was used.
function identity<T>(value: T): T {
return value;
}
const num = identity(42); // T is inferred as number, returns number
const str = identity("hello"); // T is inferred as string, returns string
// Without generics, you would need "any" (losing type safety)
// or separate functions for each type (losing reusability)Generics with Arrays
A common, practical use: a function that works with an array of any type.
function getFirstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
const firstNum = getFirstElement([1, 2, 3]); // inferred as: number | undefined
const firstName = getFirstElement(["Alice", "Bob"]); // inferred as: string | undefinedBest practices
- Use generics instead of any when a function or class should work with multiple types while still preserving type safety and autocomplete
- Let TypeScript infer the generic type argument from the actual arguments passed, rather than always specifying it explicitly (identity<string>("hi") is rarely needed)
- Use descriptive generic names (TItem, TResponse) instead of just T for complex functions with multiple type parameters, to keep signatures readable
- Reach for generics specifically when a function's behavior genuinely does not depend on the specific type - if it does, a union type or overloads may fit better
At a glance
- Purpose
- Static types for JavaScript
- File extension
- .ts ยท .tsx
- Runs in
- Compiled to JavaScript
- Usually used with
- JavaScript and its ecosystem
Specifications & further reading
Related TypeScript documentation
Generic Constraints
By default, a generic type parameter can be anything. The extends keyword constrains it to only types compatible with a given shape, letting you safely access specific properties or methods within the generic function while still supporting many different concrete types.Generic Classes and Interfaces
Classes and interfaces can also be generic, letting you build reusable data structures (like a Stack, Queue, or API response wrapper) that work with any type while remaining fully type-safe for whichever specific type is used in each instance.Conditional Types
A conditional type selects between two types based on a condition, using syntax that mirrors JavaScript's ternary operator: T extends U ? X : Y. This lets you build types that adapt based on the shape of another type, forming the foundation for many of TypeScript's built-in utility types.The infer Keyword
infer, used only within the extends clause of a conditional type, lets you declare a new type variable that captures part of a matched structure, so it can be reused in the result. It is the mechanism behind utility types like ReturnType<T> and Parameters<T>, which extract specific pieces of a function's type signature.
By default, a generic type parameter can be anything. The extends keyword constrains it to only types compatible with a given shape, letting you safely access specific properties or methods within the generic function while still supporting many different concrete types.Generic Classes and Interfaces
Classes and interfaces can also be generic, letting you build reusable data structures (like a Stack, Queue, or API response wrapper) that work with any type while remaining fully type-safe for whichever specific type is used in each instance.Conditional Types
A conditional type selects between two types based on a condition, using syntax that mirrors JavaScript's ternary operator: T extends U ? X : Y. This lets you build types that adapt based on the shape of another type, forming the foundation for many of TypeScript's built-in utility types.The infer Keyword
infer, used only within the extends clause of a conditional type, lets you declare a new type variable that captures part of a matched structure, so it can be reused in the result. It is the mechanism behind utility types like ReturnType<T> and Parameters<T>, which extract specific pieces of a function's type signature.