1. Introduction
A generic function is a function whose parameter and/or return types are expressed using one or more type parameters instead of concrete types. This lets a single function definition safely handle many different input types, while the compiler still checks that everything lines up correctly for each call — something plain JavaScript functions or any-typed functions cannot do.
Cricket analogy: A generic selectOpener<T>(players: T[]): T function can pick from a lineup of Batter objects or Allrounder objects using one definition, while the compiler still checks each call — something an any-typed selector for Rohit Sharma's team could never guarantee.
2. Syntax
// Single type parameter
function firstElement<T>(items: T[]): T {
return items[0];
}
// Multiple type parameters
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
// Generic arrow function
const wrapInArray = <T,>(value: T): T[] => [value];
// Generic function type (for variables/parameters)
let mapper: <T, U>(value: T, fn: (v: T) => U) => U;3. Explanation
Generic functions let you write reusable code that works over a variety of types while preserving type information — the return type of firstElement<T>(items: T[]): T is always exactly the element type of whatever array you pass in, never a loosely typed any. This is what distinguishes it from a version typed as (items: any[]) => any, which would lose that guarantee completely.
Cricket analogy: firstElement<T>(lineup: T[]): T returns exactly the batter type you passed in, so firstElement(kohliLineup) returns a Batter, never a loosely typed any — unlike (items: any[]) => any, which loses that guarantee entirely.
TypeScript infers type parameters from the arguments at the call site whenever possible, so most of the time you never need to write the angle brackets yourself. You only need explicit type arguments (e.g. pair<number, string>(1, "a")) when the compiler cannot infer a type unambiguously, such as when a generic function is called with no arguments that reference the type parameter.
Cricket analogy: Calling matchScore(180, "win") lets TypeScript infer the generic types from the arguments automatically, but a function called with no arguments referencing T, like starting a fresh tally<number, string>() for a new innings, needs the type arguments written explicitly.
Multi-parameter generic functions, like pair<T, U>, follow the T, K, V, U naming convention — T and U are used together when two independent, unrelated types are involved. Generic functions are also frequently combined with keyof for type-safe property access: function getProp<T, K extends keyof T>(obj: T, key: K): T[K] guarantees that key is actually a valid property name of obj, and that the return type matches that property's type exactly.
Cricket analogy: function pair<T, U>(name: T, average: U) pairs Kohli's name (T) with his batting average (U) as two unrelated types, and combining that with keyof in getProp<T, K extends keyof T>(player, key) guarantees the requested stat field truly exists.
Gotcha: in a .tsx file, <T,> (with a trailing comma) or <T extends unknown> must be used instead of plain <T> for generic arrow functions, because the parser would otherwise try to interpret <T> as the start of a JSX element.
4. Example
function firstElement<T>(items: T[]): T {
return items[0];
}
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const numbers = [10, 20, 30];
const names = ["Ada", "Grace", "Linus"];
console.log(firstElement(numbers)); // T inferred as number
console.log(firstElement(names)); // T inferred as string
const combo = pair("score", 95); // T=string, U=number
console.log(combo);
const user = { id: 1, name: "Ada Lovelace" };
console.log(getProp(user, "name")); // K constrained to 'id' | 'name'
// getProp(user, "email"); // compile error: 'email' is not a key of user5. Output
10
Ada
[ 'score', 95 ]
Ada Lovelace6. Key Takeaways
Practice what you learned
1. In `function firstElement<T>(items: T[]): T { return items[0]; }`, calling `firstElement([10, 20, 30])` infers T as:
2. Why must a generic arrow function in a `.tsx` file be written as `<T,>(value: T) => value` instead of `<T>(value: T) => value`?
3. What does the constraint `K extends keyof T` in `function getProp<T, K extends keyof T>(obj: T, key: K): T[K]` guarantee?
4. When are explicit type arguments (e.g. `pair<string, number>(...)`) required on a generic function call?
5. Which naming pattern is used when a generic function relates two independent, unrelated types?
Was this page helpful?
You May Also Like
Generics in TypeScript
Learn how TypeScript generics let you write reusable, type-safe code that works across many types without losing type information.
Generic Constraints in TypeScript
Learn how to restrict generic type parameters with `extends` so generic code can safely rely on specific properties or shapes.
keyof and typeof Operators in TypeScript
Use `keyof T` to get a union of a type's property names, and `typeof x` in a type position to extract the type of a value.
Function Overloads in TypeScript
Declare multiple callable signatures for a single function so callers get precise types for each usage pattern.
Type Inference in TypeScript
How TypeScript figures out types automatically from values, without explicit annotations.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics