{
  "id": 13350609,
  "title": "Adding Go's defer to the TypeScript Compiler",
  "url": "https://urgent.news/2026/10/10/adding-gos-defer-to-the-typescript-compiler",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-10T05:34:40.000Z",
  "source": {
    "name": "Lobsters",
    "slug": "lobsters",
    "url": "https://healeycodes.com/adding-defer-to-the-typescript-compiler"
  },
  "original_language": "en",
  "account": "Adding Go's defer statement to the TypeScript compiler was an intriguing challenge. In Go, defer delays function execution until the surrounding function completes, often used for resource cleanup. TypeScript lacks a direct equivalent, but we can replicate its behavior.\n\nTypeScript doesn't have a built-in way to implement defer. We need to output JavaScript code that mimics Go's semantics. The goal is to allow TypeScript code like this:\n\nThe TypeScript compiler is primarily a static analysis engine, mainly focused on type-checking a dynamic language. Incremental compilation ensures fast IDE response times. This simplifies our task since we don't need to worry about types or other analysis for our defer statement.\n\nAdding defer means performing another AST transformation. tsc already performs various AST-to-AST transformations, so we don't need to add new tooling. The complexity lies in teaching tsc's parser that defer is a statement.\n\nTo match Go's behavior, we need to capture the callee, receiver, and argument values immediately when the defer statement is reached. This ensures that even if the callable method is redefined later, the deferred call still invokes the original method.\n\nEach deferred call gets its own stack, and closures are pushed onto that stack when execution reaches the defer statement. When the function exits, the stack is drained in reverse order (last-in-first-out). This matches Go's behavior, where deferred calls are executed in the reverse order they were registered.\n\nTo prevent confusion, we reject defer await as an error. JavaScript exceptions are control flow, so when the compiled defer code throws an error, it needs to decide whether that error replaces, combines with, or is ignored in favor of the original failure.\n\nAfter implementing defer, I concluded that it doesn't belong in TypeScript. The more edge cases I handled, the less convinced I became about its usefulness. TypeScript's error handling and aggregation policies differ significantly from Go's, making defer less natural in TypeScript.\n\nHowever, hope isn't lost. The ECMAScript Explicit Resource Management proposal offers a different approach to the same problem. Using async-sema as an example, the proposal suggests using an unused variable to clean up resources when they fall out of scope. This approach aligns better with TypeScript's error handling and aggregation policies.",
  "summary": null,
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}