Generics Deep Dive
Generics are a powerful feature in TypeScript. They let you create reusable functions, components, and classes that can work with many different types, while still keeping type safety. In this section, we will learn how to use generics the right way, including basic generic functions, multiple type parameters, generic constraints, and generic classes. By the end of this section, you will understand how to use generics to write flexible and easy-to-maintain TypeScript code.
What Are Generics?
Section titled “What Are Generics?”Generics let you write one function or class that can work with many different types, instead of writing the same code again and again for each type. It still keeps type safety, which means TypeScript still checks everything properly.
Basic Generic Function
Section titled “Basic Generic Function”function identity<T>(value: T): T { return value;}Meaning:
- the input type is
T - the return type is also
T
So whatever type goes in, the exact same type comes out. Nothing changes.
Multiple Type Parameters
Section titled “Multiple Type Parameters”function pair<T, U>(first: T, second: U): [T, U] { return [first, second];}Use this when the two values you are working with can be different types from each other.
Generic Constraints
Section titled “Generic Constraints”function logLength<T extends { length: number }>(value: T): void { console.log(value.length);}Here, extends is used to set a rule. Now T is not just any type, it must have a length property, otherwise TypeScript will not allow it.
Generic Class
Section titled “Generic Class”class Box<T> { value: T;
constructor(value: T) { this.value = value; }}
const numberBox = new Box<number>(123);const stringBox = new Box<string>("hello");This is the same idea as before, but now used with a class instead of a function. The Box class can hold any type you give it.
Generic Data Fetch Pattern
Section titled “Generic Data Fetch Pattern”type ApiSuccess<T> = { status: "success"; data: T };type ApiError = { status: "error"; message: string };type ApiResponse<T> = ApiSuccess<T> | ApiError;
async function fetchData<T>(url: string): Promise<ApiResponse<T>> { const response = await fetch(url); if (!response.ok) { return { status: "error", message: "Request failed" }; } const data = (await response.json()) as T; return { status: "success", data };}This is a common real-world example. The fetchData function can be used to fetch any kind of data from an API, and you simply tell it what type to expect using T.