DEV Community

Cover image for TypeScript Generics Explained with Real-World Use Cases
Lia Foster
Lia Foster

Posted on

TypeScript Generics Explained with Real-World Use Cases

Introduction

Have you ever written the same function twice, just because it needed to handle two different data types? Most developers have. You either copy the function and change the type. Or you use any and give up on type checking. Neither option feels right.

This is exactly what typescript generics were built to solve. They let you write one function, one interface, or one class that works across many types. And you don't lose the type safety TypeScript is known for. According to the official TypeScript Handbook, generics let you create reusable components that work with a variety of types instead of just one. In this post, we'll cover what typescript generics are, the core ideas behind them, and a few real cases where they make a real difference.

What Are TypeScript Generics?

TypeScript generics, in essence, allow you to use a type as a variable. You don't use a specific type in a function, you create a place holder. That position will be filled in later, depending on the usage of the code. Type checker still works. It will accept any type that is passed in, rather than just a single type. It is not the same as writing untyped, loose code. The flexibility is possible here, because of the placeholder, not because of the absence of type checking.

Generics vs Using Any

Generics can be confused with the use of any everywhere. They are, however, used for solving different problems. Any signals to TypeScript to halt type checking. That's the same bugs TypeScript is here to solve. Generics maintain the type checking. The function still has an idea of what to do with it. It simply isn't pegged at a particular type from the outset.

Key Concepts Behind TypeScript Generics

There are just a handful of concepts that keep recurring as you begin to work with generics. Once you're comfortable with them, it's much easier to move on from there.

Generic Functions

A generic function accepts a type parameter as well as its conventional parameters. This means that a function can accept parameters of type string, number, object or custom types and they all can be passed safely without rewriting the function each time. The function itself stays the same. Only the type will change, depending on what is passed in. This is particularly important for functions that will be required throughout a whole project, as creating a new one for each type could prove to be quite a bit of additional work.

Generic Interfaces and Types

Generics can be used on interfaces and type aliases as well. It can be helpful for APIs response shape, or data structure reuse. Rather that create a new interface for each possible response, a single interface can define the pattern once. It then wraps itself around whatever data it has to wrap.

Generic Constraints

Sometimes limits are necessary for a generic type. Perhaps only types that have some property or method should be accepted. Constraints allow you to set that limit. This leaves it possible to make errors in the type checker even if one doesn't know the exact type in advance. This allows generics to remain flexible but not without the type safety as well.

A few more details are worth knowing, since they come up often once you start writing generic code regularly.

  • TypeScript can often figure out the type for you: In most cases, you don't need to write out the generic type by hand. TypeScript looks at what you passed in and figures it out on its own. This keeps generic code just as easy to write as regular code.

  • A function can use more than one type parameter: Real code often needs two related types at once, like a key and a value. Generics support this directly, so you don't need extra workarounds.

  • Default type parameters cut down on repetition: If a generic is used the same way most of the time, you can give it a default type. Then people only need to specify something different when they actually need to. This saves a lot of repeated typing across a codebase.

Real-World Use Cases of TypeScript Generics

Generics show up constantly in real apps, often without developers even noticing.

  • Reusable API response wrappers: Most apps get data from multiple endpoints and each endpoint returns a different structure of data. A generic response type can be used to specify the overall structure once, such as the status and data fields, and then change to accommodate any particular response.

  • Type-safe utility functions: Functions that filter a list, find an item, or group data by a key show up in almost every project. Writing them with generics means the same function works correctly on arrays of users, products, or orders, all while keeping type checking intact.

  • Custom React hooks: If you have a hook that maintains form state, fetched data, or local storage, then many times that hook will need to be implemented in more than one data structure throughout your project. A generic can be used to program a hook to adapt to any type of component passed in, rather than having to write almost the same hook for each case.

  • Shared component libraries: Teams that build internal UI libraries rely on generics a lot. A single dropdown, table, or list component needs to handle many different data types across different parts of an app. If your team is building something like this, it's often worth choosing to hire TypeScript developers who already have real experience designing reusable, generic components.

Conclusion

TypeScript generics aren't some advanced feature meant only for library authors. They're a practical tool that shows up in everyday code more often than most developers realize. Once the core idea makes sense, treating a type like a variable instead of a fixed value, a lot of repeated code starts to disappear. In its place, you get fewer functions and interfaces that do more work.

As more teams adopt TypeScript, learning generics is becoming less of an extra skill and more of a basic one. If your codebase is full of near-duplicate functions or loosely typed data, generics are usually the cleanest fix. Start small with one reusable function or interface. From there, the pattern tends to spread naturally as the rest of the codebase benefits from it too.

Top comments (4)

Collapse
 
dhruvil_joshi14 profile image
Dhruvil Joshi

Nice balance between theory and real implementation, very helpful.

Collapse
 
maitri profile image
maitri

Great explanation of TypeScript generics, especially the real-world use cases.

Collapse
 
mindy_collins_ profile image
Mindy Collins

Helpful read, especially for developers trying to move beyond basic TypeScript.

Collapse
 
emiliabennett profile image
emilia

Clean and beginner-friendly explanation of a topic many devs struggle with.