Skip to main content

What are Generics in TypeScript?

ยท 5 min read

TypeScript generics are a powerful feature that allows you to create reusable and flexible components, functions, and classes by defining them with a type variable.

Understanding Generics ๐Ÿค”โ€‹

This type variable, often denoted as <T>, can be used in place of specific types, enabling you to write code that can work with multiple types without sacrificing type safety.

Generics promote code reusability and maintainability, as you can write a single, generalized function, class, or interface that can be used with different types, rather than creating separate implementations for each specific type.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

Basic Synxtax ๐Ÿ“โ€‹

The simplest form of TypeScript generics syntax is the type variable, usually represented by a single letter like <T>.

Here's a minimal example of a generic function:

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

In this example:

  1. <T> is the type variable. It acts as a placeholder for the actual type that will be provided when the function is called.
  2. function identity<T>(arg: T): T is the generic function declaration. The type variable <T> is placed right after the function name and before the parameter list.
  3. arg: T specifies that the input parameter arg is of type T. It means that the type of arg will be the same as the type provided when calling the function.
  4. : T after the parameter list indicates that the return type of the function is also of type T. The function will return a value of the same type as the input parameter.

Now, when you call the identity function, you can either explicitly provide the type, like identity<number>(42), or let TypeScript infer it based on the provided argument, like identity(42). In both cases, the function will return a value of the same type as the input, and TypeScript will ensure type safety.

Generics With Classesโ€‹

Generics can also be used with classes, interfaces, and type aliases. Here are examples for each of these constructs using generic types:

class Box<T> {
private content: T;

constructor(content: T) {
this.content = content;
}

getContent(): T {
return this.content;
}
}

In this example, the Box class has a generic type <T>. It is used as the type of the content property and the type of the parameter in the constructor. The getContent() method also returns a value of type T. This makes the Box class generic and able to store and return content of any type.

Generics With Interface:โ€‹

interface KeyValuePair<K, V> {
key: K;
value: V;
}

In this example, the KeyValuePair interface has two generic types: <K> and <V>. These types represent the key and value in a key-value pair, allowing you to define objects with keys and values of any type.

Generics With Type Aliases:โ€‹

type Callback<T> = (arg: T) => void;

In this example, the Callback type alias is a generic function type with a single type variable <T>. It represents a function that takes a single argument of type T and returns nothing (void). This allows you to create callback functions with different argument types while maintaining type safety.

Real World Examples ๐ŸŒŽโ€‹

A real-world application of generics in type aliases can be seen in the context of a React application. Suppose you're building a blog and need a standardized way to represent the API response for a list of entities, such as posts or comments.

You can create a generic type alias to represent paginated results from the API:

type PaginatedResults<T> = {
data: T[];
currentPage: number;
totalPages: number;
};

interface Post {
id: number;
title: string;
content: string;
}

interface Comment {
id: number;
postId: number;
text: string;
}

In this example, the PaginatedResults type alias has a single generic type <T>. It is used as the type for the data property, which is an array of items of type T. This allows you to represent paginated results for various types of entities, such as Post or Comment.

Now, when you fetch data from the API, you can define the expected response type using the PaginatedResults type alias:

async function fetchPosts(page: number): Promise<PaginatedResults<Post>> {
// Mock data for posts
const dummyPosts: Post[] = [
{ id: 1, title: "Dummy Post 1", content: "This is a dummy post." },
{ id: 2, title: "Dummy Post 2", content: "This is another dummy post." },
];

const paginatedResults: PaginatedResults<Post> = {
data: dummyPosts,
currentPage: 1,
totalPages: 1,
};

// Return dummy data as PaginatedResults<Post>
return paginatedResults;
}

async function fetchComments(page: number): Promise<PaginatedResults<Comment>> {
// Mock data for comments
const dummyComments: Comment[] = [
{ id: 1, postId: 1, text: "This is a dummy comment." },
{ id: 2, postId: 2, text: "This is another dummy comment." },
];

const paginatedResults: PaginatedResults<Comment> = {
data: dummyComments,
currentPage: 1,
totalPages: 1,
};

// Return dummy data as PaginatedResults<Comment>
return paginatedResults;
}

By using the PaginatedResults generic type alias, you can ensure type safety and maintain a consistent structure for API responses throughout your application, regardless of the specific entities being fetched.

What Can You Do Next ๐Ÿ™๐Ÿ˜Šโ€‹

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.

YouTube @cloudaffle