Generics in JavaScript: Why They Are Needed and How to Use Them for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

What are Generics in JavaScript and Why Are They Needed?

\n\n

Imagine you are writing a function that should work with different data types — numbers, strings, objects. Without Generics, you would either have to duplicate code or use any, losing control over types. Generics are a mechanism that allows you to create components (functions, classes, interfaces) that work with any data type while preserving type information.

\n\n

Although JavaScript is a dynamically typed language, the Node.js ecosystem actively uses TypeScript, which adds static typing. It is in TypeScript that generics truly shine. However, understanding their principles is also useful for plain JavaScript — especially if you write libraries or work with modern frameworks.

\n\n

In this article, we will cover:

\n
    \n
  • Why Generics are needed
  • \n
  • How to declare and use generics in TypeScript
  • \n
  • Examples for Node.js (API, data processing)
  • \n
  • Limitations and best practices
  • \n
\n\n

Generics Basics: Syntax and Basic Examples

\n\n

First Generic: The identity Function

\n\n

A classic example is a function that returns what it receives as input:

\n\n
// Without Generics\nfunction identity(value: any): any {\n  return value;\n}\n\n// With Generics\nfunction identity<T>(value: T): T {\n  return value;\n}\n\n// Usage\nconst num = identity<number>(42);    // num — number\nconst str = identity<string>('hello'); // str — string\n
\n\n

The symbol <T> is a type parameter. You can name it anything (T, U, Item), but tradition dictates using T (from Type).

\n\n

Generics with Multiple Parameters

\n\n

Sometimes you need to work with multiple types simultaneously:

\n\n
function pair<T, U>(first: T, second: U): [T, U] {\n  return [first, second];\n}\n\nconst result = pair<number, string>(1, 'one');\n// result: [number, string]\n
\n\n

Generics in Arrow Functions (Node.js)

\n\n

In React or utility functions, arrow functions with generics are often used:

\n\n
const wrapInArray = <T>(item: T): T[] => {\n  return [item];\n};\n\nconst arr = wrapInArray('test'); // arr: string[]\n
\n\n

Applying Generics in Real Node.js Projects

\n\n

API Handlers with Typed Responses

\n\n

Imagine you are writing a universal function for API requests. Without generics, you would lose data types:

\n\n
// Bad: any\nasync function fetchData(url: string): Promise<any> {\n  const response = await fetch(url);\n  return response.json();\n}\n\n// Good: Generics\nasync function fetchData<T>(url: string): Promise<T> {\n  const response = await fetch(url);\n  return response.json();\n}\n\n// Usage\ninterface User {\n  id: number;\n  name: string;\n}\n\nconst user = await fetchData<User>('/api/user/1');\nconsole.log(user.name); // TypeScript knows that name is a string\n
\n\n

Typed Data Collections

\n\n

When working with databases (e.g., via Prisma or Mongoose), generics help create universal repositories:

\n\n
class Repository<T extends { id: number }> {\n  private items: T[] = [];\n\n  add(item: T): void {\n    this.items.push(item);\n  }\n\n  getById(id: number): T | undefined {\n    return this.items.find(item => item.id === id);\n  }\n}\n\n// Usage\ninterface Product {\n  id: number;\n  title: string;\n  price: number;\n}\n\nconst productRepo = new Repository<Product>();\nproductRepo.add({ id: 1, title: 'Laptop', price: 1000 });\nconst laptop = productRepo.getById(1);\n
\n\n

Wrappers for Error Handling

\n\n

A universal function for

Blogs

Book Recommendations