Introduction: Why Caching Is Critically Important for TypeScript Applications
Modern TypeScript web applications face growing loads and speed requirements. Caching is not just an option, but a necessity for any production-grade application. Without it, every request to a database or external API becomes an expensive operation, increasing response time by 10-100 times.
In this article, we will break down three main approaches to caching in TypeScript: Redis — a distributed cache, Memcached — a lightweight alternative, and built-in solutions (in-memory cache). You will learn how to choose the right tool and implement it with code examples.
1. Built-in Caching: In-Memory Cache in TypeScript
The simplest and fastest way is to store data directly in the process's RAM. For TypeScript/Node.js, this is ideal for monolithic applications or single-instance microservices.
Implementing a Simple In-Memory Cache
Let's create a SimpleCache class with TTL (time-to-live) support:
interface CacheEntry<T> { value: T; expiresAt: number;}
class SimpleCache<T> { private store = new Map<string, CacheEntry<T>>(); private defaultTTL: number; // in milliseconds
constructor(defaultTTL: number = 60000) { this.defaultTTL = defaultTTL; }
set(key: string, value: T, ttl?: number): void { const expiresAt = Date.now() + (ttl ?? this.defaultTTL); this.store.set(key, { value, expiresAt }); }
get(key: string): T | null { const entry = this.store.get(key); if (!entry) return null; if (Date.now() > entry.expiresAt) { this.store.delete(key); return null; } return entry.value; }
has(key: string): boolean { return this.get(key) !== null; }
delete(key: string): void { this.store.delete(key); }
clear(): void { this.store.clear(); }}
// Usage exampleconst userCache = new SimpleCache<User>(30000); // TTL 30 secondsuserCache.set('user:123', { id: 123, name: 'Anna' });const cachedUser = userCache.get('user:123');Pros and Cons of In-Memory Cache
- Pros: maximum speed (nanoseconds), no network latency, simple implementation.
- Cons: data is lost on application restart, limited by a single process's RAM, does not work with horizontal scaling.
When to use: for caching results of heavy computations, configurations, static data that rarely changes.
2. Redis: Distributed Caching for TypeScript
Redis is the most popular in-memory data store, used as a cache, message broker, and database. For TypeScript, we use the ioredis library.
Installation and Basic Setup
npm install ioredisnpm install @types/ioredis -DLet's create a service for working with Redis:
import Redis from 'ioredis';
class RedisCacheService { private client: Redis; private defaultTTL: number;
constructor(ttlSeconds: number = 3600) { this.client = new Redis({ host: process.env.REDIS_HOST || 'localhost', port: Number(process.env.REDIS_PORT) || 6379, retryStrategy: (times) => Math.min(times * 50, 2000), }); this.defaultTTL = ttlSeconds; }
async set<T>(key: string, value: T, ttl?: number): Promise<void> { const serialized = JSON.stringify(value); const ttlToUse = ttl ?? this.defaultTTL; await this.client.setex(key, ttlToUse, serialized); }
async get<T>(key: string): Promise<T | null> { const data = await this.client.get(key); if (!data) return null; try { return