TypeScript Generics Explained with Examples: A Beginner's Guide

Learn how TypeScript generics work with simple, practical examples. Understand generics step-by-step to write flexible, reusable code in TypeScript.

If you're beginning to learn TypeScript and want your code to be more flexible and reusable, understanding generics is essential. Generics allow you to write functions, classes, and interfaces that work with a variety of types without losing type safety. This tutorial will guide you through what TypeScript generics are, why they matter, and how to use them effectively with straightforward examples.

At its core, a generic is like a placeholder for a type. Instead of explicitly defining the type inside your function or class, you use a generic parameter that is specified later. This means you can write one piece of code that adapts to different data types as needed. Generics work well alongside other TypeScript features like interfaces, type aliases, and type inference, making your code more robust and maintainable.

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

const num = identity<number>(42); // num is number
const str = identity<string>('hello'); // str is string

// Generic with arrays
type Box<T> = {
  contents: T[];
};

const numberBox: Box<number> = { contents: [1, 2, 3] };
const stringBox: Box<string> = { contents: ['a', 'b', 'c'] };

To use generics properly, start by declaring a generic parameter inside angle brackets, like . You can then use T as a type within your function, class, or interface. When calling or instantiating your generic code, specify the actual type you want, or let TypeScript infer it for you. This approach avoids repeating similar functions for different types and keeps your code DRY (Don't Repeat Yourself). You can also constrain generics to specific types to enforce more precise typing.

Common mistakes with generics include not specifying a type parameter, which can lead to the type defaulting to unknown or any, reducing type safety. Another error is overusing generics where simpler types would do, making the code unnecessarily complex. Additionally, forgetting to add constraints when a generic type needs certain properties can cause runtime errors or difficult-to-debug code. Always balance flexibility with clear intent using constraints and type inference.

In summary, TypeScript generics are a powerful way to write flexible and reusable code while maintaining strong typing. They work hand in hand with other TypeScript concepts like interfaces, type aliases, and type inference. By mastering generics, you can avoid duplication and build more maintainable applications. Keep practicing with simple examples and gradually add complexity once you're comfortable with the basics.