What it measures

Closure Depth counts how many function scopes are nested inside one another, starting from 1 for the outermost function. A standalone function has depth 1; a callback inside it has depth 2; a callback inside that has depth 3, and so on.

High closure depth is a classic sign of callback hell — deeply nested asynchronous callbacks that are hard to read, test, and reason about.

How it's computed

tsmetrics walks the AST and increments a depth counter each time it enters a function node (function_declaration, function_expression, arrow_function, or method_definition). The maximum depth seen in the file is reported.

depth(node) = 1 + max(depth(child) for child in function_children(node))

Examples

TypeScript — depth 1 (clean)
function fetchUser(id: string) {
  return db.query(id);
}
TypeScript — depth 4 (callback hell)
function fetchData() {          // depth 1
  doA(function() {              // depth 2
    doB(function() {            // depth 3
      doC(() => { /* … */ });  // depth 4
    });
  });
}
Tip: Refactor deeply nested callbacks using async/await, named functions, or Promise chaining. Aim for closure depth ≤ 2.

Interpretation

DepthMeaning
1Single function — no nesting
2One level of callbacks — generally fine
3Starting to get complex — consider refactoring
4+Callback hell — refactor with async/await or named functions
Edit on GitHub