JavaScript Edge Cases
Language quirks, async patterns, and runtime gotchas
Start Here
Essential reads to understand the key concepts and patterns.
Browser Event Loop: Why Promise Callbacks Don't Always Run First
Microtasks run when the JS stack empties, not just at task boundaries. This changes behavior with event bubbling, .click(), and recursive promises.
Promise.withResolvers(): The Pattern You've Been Hacking Around
Promise.withResolvers() eliminates the deferred promise hack, but leaked resolvers create memory leaks that are harder to spot than the old pattern.
structuredClone(): The Deep Copy That Isn't Always Deep
structuredClone() handles circular refs and built-in types, but silently drops prototypes, class instances, getters, and Symbol properties.
JavaScript Decorators (TC39 Stage 3): The Breaking Change from Legacy
TC39 Stage 3 decorators are incompatible with TypeScript's legacy implementation — here's what changed
Explicit Resource Management: using and Symbol.dispose
JavaScript's answer to RAII — automatic cleanup for file handles, locks, and event listeners that actually runs.
More Articles
Node.js TypeScript Type Stripping: What Works and What Breaks
Run .ts files directly in Node.js — but know what breaks
JavaScript Iterator Helpers: Lazy .map(), .filter(), and .take()
Lazy .map(), .filter(), and .take() for iterators — and the gotchas
JavaScript Temporal API Gotchas: What Breaks When Migrating from Date
JavaScript's Temporal API replaces Date, but brings new complexity. DST ambiguity, Plain vs Zoned types, and strict parsing will trip up migrating teams.