Introduction: Why Algorithms and Data Structures Matter in TypeScript?
In modern web development, TypeScript holds a leading position, offering strict typing and powerful tools for creating scalable applications. However, even the most elegant code will not be efficient without an understanding of fundamental algorithms and data structures. This article is your guide to the world of optimized code in TypeScript. We will break down key data structures, show how to implement them with types in mind, and examine classic algorithms. After reading, you will be able to write not only working, but also fast, predictable code.
1. Basic Data Structures with Typing
TypeScript allows you to strictly define which data types can be stored in a structure. This prevents errors at the compilation stage. Let's look at three fundamental structures.
1.1. Stack — LIFO Principle
A stack works on the principle "Last In, First Out". It is ideal for tasks where you need to undo actions (for example, browser history).
// Stack implementation with generic Tclass Stack<T> { private items: T[] = [];
push(item: T): void { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
peek(): T | undefined { return this.items[this.items.length - 1]; }
isEmpty(): boolean { return this.items.length === 0; }}
// Usage exampleconst numberStack = new Stack<number>();numberStack.push(10);numberStack.push(20);console.log(numberStack.pop()); // 201.2. Queue — FIFO Principle
A queue works on the principle "First In, First Out". It is used for processing tasks in the order they arrive, for example, in message queue systems.
class Queue<T> { private items: T[] = [];
enqueue(item: T): void { this.items.push(item); }
dequeue(): T | undefined { return this.items.shift(); }
front(): T | undefined { return this.items[0]; }
size(): number { return this.items.length; }}
// Example with custom typeinterface Task { id: number; name: string;}const taskQueue = new Queue<Task>();taskQueue.enqueue({ id: 1, name: 'Process order' });taskQueue.enqueue({ id: 2, name: 'Send email' });1.3. Linked List
A linked list consists of nodes, each of which references the next one. Unlike an array, inserting and deleting elements in the middle of the list does not require shifting all elements.
class ListNode<T> { value: T; next: ListNode<T> | null = null;
constructor(value: T) { this.value = value; }}
class LinkedList<T> { private head: ListNode<T> | null = null;
add(value: T): void { const newNode = new ListNode(value); if (!this.head) { this.head = newNode; return; } let current = this.head; while (current.next) { current = current.next; } current.next = newNode; }
print(): void { let current = this.head; while (current) { console.log(current.value); current = current.next; } }}
// Usageconst list = new LinkedList<string>();list.add('TypeScript');list.add('Python');list.print(); // TypeScript, Python2. Sorting and Searching Algorithms
Sorting data is one of the most common operations. TypeScript allows you to create universal functions that work with any data types.
2.1. Quick Sort
One of the most efficient algorithms with