⚡ JavaScript

Generics and Parameterized Types in JavaScript (Node.js): A Detailed Guide Introduction In the world of modern programming, type safety and code reusability are becoming increasingly important. One of the key tools for

What is it and why? (a real-life analogy)

Imagine you work in a toy warehouse. You have three boxes:

  • Box for cars — you can only put cars in it.
  • Box for dolls — only for dolls.
  • Box for construction sets — only for construction sets.

Every time you want to put something new away, you need to run and get a new box. That's inconvenient, right?

Now imagine a universal box. It's not labeled "for cars" or "for dolls." It simply says: "For toys." You can put a car in it, then a doll, then a construction set — and the box will work just as well. But there is one rule: if you decide that this box will only contain cars, you can no longer put a doll in it — the box will "remember" your choice.

In programming, such "universal boxes" are called generics (from the English word generic — general, generic). And the "type of toy" that we specify when creating the box is called a parametric type.

💡 Important note: In JavaScript (especially Node.js), generics didn't appear right away. For a long time, JS was "dynamic" — you could put anything in a box, and no one checked. But with the advent of TypeScript (a superset of JS) and modern development tools, generics became necessary for writing reliable code.

Why is this needed?

  • Type safety: If you say "this box is only for cars," the compiler won't let you accidentally put a doll in it.
  • Code reuse: One function can work with numbers, strings, objects — you don't need to write three different functions.
  • Readability: Other programmers can immediately see what data types are expected.

Theory: how it works internally

Let's look "under the hood" and understand what happens when we use generics.

What is a "type" in programming?

A type is a set of rules that describe what can be done with data. Numbers can be added, strings can be concatenated, arrays can be iterated. When we say "this variable is a number," we promise the computer: "I will only work with it as a number."

The problem without generics

Imagine a function that returns the first element of an array:

// Without generics — you have to use any
function getFirstElement(arr) {
    return arr[0];
}

const numbers = [1, 2, 3];
const firstNumber = getFirstElement(numbers); // Type: any — we lost the information!

// Now we can accidentally do:
const length = firstNumber.length; // Error! Numbers don't have length, but the compiler is silent

The problem is that we lost the type information. The computer no longer knows if there was a car or a doll inside — it just sees "something."

How generics solve this problem

Generics work like variables for types. Instead of writing a specific type (number, string), we write a type parameter — usually denoted by letters T, U, V or meaningful words.

// With generics — the type is preserved!
function getFirstElement<T>(arr: T[]): T {
    return arr[0];
}

const numbers = [1, 2, 3];
const firstNumber = getFirstElement(numbers); // Type: number — information preserved!

// Now the compiler won't let us do:
const length = firstNumber.length; // ❌ Error! Property 'length' does not exist on type 'number'

What happened here?

  1. <T> — we declared a type parameter T. It's like a variable, but for types.
  2. arr: T[] — an array of elements of type T.
  3. : T — the function returns a value of type T.
  4. When we called the function with an array of numbers, TypeScript automatically substituted T = number.

How it looks in memory

When you write const box = new Box<number>(), the compiler creates a "snapshot" of the class where all T's are replaced with number. This is called monomorphization. In JavaScript (via TypeScript), this doesn't happen directly — TS just checks types at compile time, and at runtime JS works as usual.

🔧 Technical detail: Unlike Java or C#, where generics exist at runtime as well, in TypeScript they are completely erased after compilation. This is called "type erasure." That is, generics are only for checking at the code-writing stage; they don't exist in the final JS.

Syntax in JavaScript (Node.js): all forms and variations

It's important to understand: pure JavaScript does not support generics. They only exist in TypeScript, which compiles to JS. But since a modern Node.js project without TypeScript is rare, we will look at TypeScript syntax.

1. Basic form with one parameter

// The simplest case — one type parameter T
function identity<T>(value: T): T {
    return value;
}

// Usage:
const num = identity<number>(42);    // num: number
const str = identity<string>("hello"); // str: string
// You can omit the type — TS will infer it:
const auto = identity(true); // auto: boolean

2. Multiple type parameters

// When you need to work with two different types
function pair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

const result = pair<number, string>(1, "one");
// result: [number, string]

3. Constraints

// We can say: "T must