TYPESCRIPT

TypeScript Generics: Syntax, Usage, and Examples

Generics in TypeScript let you create flexible and reusable components that adapt to different types. Instead of hardcoding types, you can define functions, classes, and interfaces that handle multiple data types while maintaining type safety. This makes your code more scalable and prevents unnecessary duplication.

How to Use Generics in TypeScript

To define a generic, use angle brackets (<>) with a type parameter.

function identity<T>(arg: T): T {
  return arg;
}

console.log(identity<string>("Hello")); // Output: Hello
console.log(identity<number>(42)); // Output: 42

Here, T acts as a placeholder for any type. When calling the function, you can specify the actual type, or TypeScript will infer it for you.

Generic Functions

A generic function adapts to different input types while maintaining type safety.

function getFirst<T>(arr: T[]): T {
  return arr[0];
}

console.log(getFirst([10, 20, 30])); // Output: 10
console.log(getFirst(["a", "b", "c"])); // Output: "a"

Since getFirst uses a generic parameter, you don’t need to write separate functions for different array types.

Generic Interfaces

You can use generics in interfaces to define flexible data structures.

interface Box<T> {
  value: T;
}

let numberBox: Box<number> = { value: 123 };
let stringBox: Box<string> = { value: "Hello" };

console.log(numberBox.value); // Output: 123
console.log(stringBox.value); // Output: Hello

With a generic interface, you create structured objects that work with different types.

Generic Classes

You can also use generics in classes to build reusable components.

class Storage<T> {
  private data: T[] = [];

  addItem(item: T): void {
    this.data.push(item);
  }

  getItems(): T[] {
    return this.data;
  }
}

const numberStorage = new Storage<number>();
numberStorage.addItem(10);
numberStorage.addItem(20);
console.log(numberStorage.getItems()); // Output: [10, 20]

const stringStorage = new Storage<string>();
stringStorage.addItem("Apple");
console.log(stringStorage.getItems()); // Output: ["Apple"]

This approach keeps your code type-safe while allowing different types of data.

When to Use Generics in TypeScript

Use generics when you need reusable, type-safe functions or data structures. They work well for utility functions like sorting or filtering, where the type may vary. If you're building APIs, generics let you enforce strict type definitions while keeping things flexible.

Generics also help eliminate redundancy. Instead of writing multiple versions of a function for different types, you create one generic implementation that handles them all.

Examples of Generics in TypeScript

Adding Constraints to Generics

Sometimes, you need to ensure a generic type has certain properties. You can use constraints to enforce this.

interface Lengthy {
  length: number;
}

function getLength<T extends Lengthy>(item: T): number {
  return item.length;
}

console.log(getLength("Hello")); // Output: 5
console.log(getLength([1, 2, 3])); // Output: 3

By extending Lengthy, this function only accepts types with a length property.

Generic Arrow Functions

You can also use generics in arrow functions for cleaner syntax.

const reverseArray = <T>(items: T[]): T[] => items.reverse();

console.log(reverseArray([1, 2, 3])); // Output: [3, 2, 1]
console.log(reverseArray(["a", "b", "c"])); // Output: ["c", "b", "a"]

This approach makes generic functions more concise and readable.

Working with Multiple Type Parameters

A function can use multiple generic parameters to handle different types.

function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

const person = merge({ name: "Alice" }, { age: 30 });
console.log(person); // Output: { name: "Alice", age: 30 }

Here, merge takes two objects with different types and merges them into one.

Learn More About TypeScript Generics

Optional Generics

You can set a default type for generics, making them optional.

function wrapValue<T = string>(value: T): { wrapped: T } {
  return { wrapped: value };
}

console.log(wrapValue(42)); // Output: { wrapped: 42 }
console.log(wrapValue()); // Output: { wrapped: "" } (default type is string)

This makes your functions more adaptable without requiring explicit type arguments.

Generics with Object Types

Generics let you enforce type safety while working with objects.

function extractProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const user = { name: "John", age: 28 };
console.log(extractProperty(user, "name")); // Output: John

This function ensures that key is a valid property of the object.

Generic Arrays

Generics help when filtering or modifying arrays while maintaining consistent types.

function filterItems<T>(arr: T[], predicate: (item: T) => boolean): T[] {
  return arr.filter(predicate);
}

console.log(filterItems([1, 2, 3, 4], (n) => n > 2)); // Output: [3, 4]
console.log(filterItems(["apple", "banana"], (s) => s.includes("a"))); // Output: ["banana"]

This makes array operations more flexible without losing type safety.

Advanced Generic Constraints

You can enforce stricter constraints to refine generic behavior.

interface HasId {
  id: number;
}

function findById<T extends HasId>(items: T[], id: number): T | undefined {
  return items.find((item) => item.id === id);
}

const users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
console.log(findById(users, 2)); // Output: { id: 2, name: "Bob" }

This function ensures only objects with an id property can be used.

Checking Generic Types at Runtime

Since TypeScript types disappear at runtime, you can’t directly check a generic type. However, you can enforce constraints.

function isString<T>(value: T): boolean {
  return typeof value === "string";
}

console.log(isString("hello")); // Output: true
console.log(isString(100)); // Output: false

This function provides a way to check types without losing generic flexibility.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH