All posts

Fix Memory Leak in TypeScript

Diagnose and fix memory leaks in TypeScript/Node.js applications from closures, EventEmitters, and WeakRef misuse.

Memory Leaks in TypeScript/Node.js

TypeScript compiles to JavaScript, so memory leaks in TypeScript apps are JavaScript leaks at runtime. Here are patterns specific to typed Node.js applications.

Closure Captures

TypeScript closures capture variables by reference. Large objects referenced inside callbacks persist:

function processData(largeBuffer: Buffer): () => number {
  // The entire largeBuffer is retained because the closure references it
  return () => largeBuffer.length;
}

// FIX: capture only what you need
function processData(largeBuffer: Buffer): () => number {
  const len = largeBuffer.length;
  return () => len;
}

EventEmitter Listener Buildup

Node warns at 11 listeners, but by then you're already leaking:

class DataProcessor {
  constructor(private emitter: EventEmitter) {
    // BAD: called every time a request comes in
    this.emitter.on('data', this.handleData.bind(this));
  }

  // GOOD: add once, or clean up
  destroy() {
    this.emitter.removeListener('data', this.boundHandler);
  }
}

Map and Set Without Cleanup

// LEAK: keys are never removed
const cache = new Map<string, ExpensiveObject>();

// FIX: use WeakRef or FinalizationRegistry
const cache = new Map<string, WeakRef<ExpensiveObject>>();

function get(key: string): ExpensiveObject | undefined {
  const ref = cache.get(key);
  const obj = ref?.deref();
  if (!obj) cache.delete(key);
  return obj;
}

Heap Snapshots

node --inspect dist/server.js
# Connect Chrome DevTools → Memory → Take Heap Snapshot

Bugsly integrates with Node.js process metrics and captures heap growth trends, alerting your team when memory consumption deviates from baseline.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free