TypeScript Generics and Function Types

Published Updated

TypeScript generics help you reuse functions and data types without discarding type information. Start with function signatures, then learn how type parameters connect inputs and outputs. Built-in utility types let you adapt types you already have.

These three fit together more tightly than their names suggest. A utility type such as ReturnType is a generic type applied to a function type, so the vocabulary of the first guide shows up in the last one. Read them in order if any of that is new.

TypeScript Generics Topics

  • Typing Functions and Callbacks covers parameters, return types, optional and rest parameters, callback types, and where contextual typing saves you the annotation.
  • Generic Functions and Types covers type parameters, inference at the call site, constraints with extends, and defaults.
  • Utility Types covers the built-in transformers such as Pick, Omit, Partial, Record, and ReturnType, plus when a named type beats a clever one.

What Are TypeScript Generics?

TypeScript generics let a function, interface, or type alias accept type parameters. A type parameter preserves the relationship between a caller's input and the result without using any. Compare these two functions:

// a value parameter: the caller supplies the value
function identityValue(value: string): string {
  return value;
}

// a type parameter: the caller supplies (or the compiler infers) the type
function identity<Value>(value: Value): Value {
  return value;
}

const label = identity("draft");
const count = identity(3);

// hover in an editor shows:
// const label: "draft"
// const count: 3

The compiler read each call and filled Value in for you, which is inference doing the same job it does for ordinary variables. Those two results are literal types because the arguments were literals passed straight into an unconstrained type parameter; the same calls assigned through a wider annotation would widen to string and number.

The second half of the rule is that all of this disappears. Type parameters, constraints, and utility types are part of the type layer, so compilation erases them and the emitted JavaScript holds one plain function. That is why a generic cannot inspect its own type argument at runtime. There is nothing left to inspect. Checking what a value actually is remains a narrowing problem, which the types topic covers.

Common Pitfalls

  • A type parameter used once: if T appears in exactly one position and nowhere else, it is usually not connecting anything, though a parameter used once can still capture a type for a later inference. The generics guide covers the test for whether a parameter is pulling weight.
  • Annotating callback parameters that infer: a callback passed straight into a typed parameter is contextually typed already. The functions guide shows where that inference applies and where it stops.
  • Reaching for any to make a helper reusable: that stops checking the affected values and loses information about the return type. A type parameter keeps the caller's type instead of discarding it.
  • Nesting utility types until nobody can read them: Partial<Pick<User, "email">> is fine once. Repeated in three files, it wants a name, as the utility types guide argues.

Frequently Asked Questions

What does T mean in TypeScript generics?

In TypeScript generics, T is a type parameter name, just as x can be a value parameter name. The single letter is a convention inherited from other languages, not a rule. GenericItem or ItemType compiles identically. Longer names usually read better once a helper takes more than one type parameter.

Do TypeScript generic calls need explicit type arguments?

TypeScript generic calls usually do not need explicit type arguments because the compiler can infer them from the supplied values. Some positions provide no inference candidate, and NoInfer deliberately excludes one. You supply it yourself when the call constrains nothing, or when you want a wider type than inference picked.

Do TypeScript generics slow down JavaScript at runtime?

TypeScript generics do not add runtime overhead to the JavaScript they produce. Type parameters disappear during compilation, leaving an ordinary function. The cost lands on the compiler and the editor, which is why deeply nested generic types can slow type checking while leaving runtime performance untouched.

Continue Learning TypeScript

  • Start with TypeScript Types if annotations, interfaces, and unions are still new. Everything here builds on them.
  • Move on to TypeScript Tooling for tsconfig.json, the compiler flags that change how strict all of this is, React props, and API contracts.
  • Return to the TypeScript guide for the language overview and the full learning path.

Sources

  1. [1]
    More on Functions
    (typescriptlang.org)
  2. [2]
    Generics
    (typescriptlang.org)
  3. [3]
    Utility Types
    (typescriptlang.org)