What are generics in TypeScript?

Generics are building components in TypeScript that are reusable and capable of working with multiple types of data rather than just one. They provide a way to create flexible code by allowing functions, classes, or interfaces to use any data type when they are called.

Let’s look at an example to help you understand. This may now be accomplished by defining an identity function of type any.

function identity(arg: any): any {
return 101;
}
let str = identity("How you doin");
console.log(typeof str); // displays the type of output
console.log(str); // displays the output

The above method does fulfill the requirement of getting any data in the function. However, it does not keep track of the data type that was passed to the function in the first place and allows a different return type. It can be observed in the code above that we are passing a string and returning a number. A generic component, however, does not allow this type of behavior. It only returns the type that was passed to it as input.

Types of generics

For generics, we use a special kind of variable Type that can take in any data type. Let’s go through different types of generics in TypeScript:

Function generics

A generic function can accept any type and return the same type. To further comprehend this notion, consider the following code sample.

function identity<Type>(arg: Type): Type {
return arg;
}
let str = identity<string>("Hello");
console.log(typeof str);
console.log(str); // Output: Hello
let num = identity<number>(42);
console.log(typeof num);
console.log(num); // Output: 42

Here’s a brief overview of the code above:

  • Lines 1–3: This is a generic function named identity. It takes in and returns a single argument of type Type. The <Type> type indicates that identity function could work with any type of data that is input to the function.

  • Lines 5–7: This is a call to identity function with string type data. After that, the type of the data and data itself is printed.

  • Lines 9–11: This is a call to identity function with number type data. After that, the type of the data and data itself is printed.

Note: If you replace the arg in line 2, with a number, it will return an error because the input type is a string, and we are returning a number.

Class generics

A generic class can work with any specific data type. To further comprehend this notion, consider the following code sample:

class StackOperations<Type> {
private stack: Type[];
constructor() {
this.stack = [];
}
appendItem(item: Type): void {
this.stack.push(item);
}
deleteItem(): Type[] {
this.stack.pop();
return this.stack;
}
getStack(): Type[] {
return this.stack;
}
}
let stringStack = new StackOperations<string>();
stringStack.appendItem("Red");
stringStack.appendItem("Blue");
stringStack.appendItem("Green");
console.log(stringStack.getStack());
stringStack.deleteItem();
console.log(stringStack.getStack());
let numberStack = new StackOperations<number>();
numberStack.appendItem(1);
numberStack.appendItem(2);
numberStack.appendItem(3);
console.log(numberStack.getStack());
numberStack.deleteItem();
console.log(numberStack.getStack());

Here’s a brief overview of the code above:

  • Lines 1–19: This is a generic class StackOperations with a private property stack, and methods constructor(), appendItem(), deleteItem(), and getStack(). These methods are used to initialize the stack property, add an item at its end, delete the last item, and get the stack respectively.

  • Lines 23–29: A new string type instance of StackOperations class is created, and three strings are appended to it, then the stack is displayed, followed by the deletion of the last appended string in the stack. At last, the stack is displayed again.

  • Lines 32–38: A new number type instance of StackOperations class is created, and three numbers are appended to it, then the stack is displayed, followed by the deletion of the last appended number in the stack. At last, the stack is displayed again.

Interface generics

We can define generic interfaces that can work with different data types. We create instances of different specific types that can use the interface. For example, instances of a generic Types can hold different types of values. To further comprehend this notion, consider the following code sample:

interface Types<Type> {
value: Type;
}
const text: Types<string> = {
value: "How you doin!"
};
const numbers: Types<number> = {
value: 101
};
const booleans: Types<boolean> = {
value: false
};
console.log(text.value);
console.log(numbers.value);
console.log(booleans.value);

Here’s a brief overview of the code above:

  • Lines 1–3: An interface Types that can hold any type of data.

  • Lines 5–15: Three instances of Types interface that can hold string, number, and boolean data types.

  • Lines 17–19: Display all the instances.

Generics are type-safe because they preserve the type data at compile-time. They are a type of function that can adapt to different data types without having to check the type of data.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved