Skip to the solution
HardFrontend10 min read

How do you type and compose multiple disposables with DisposableStack and AsyncDisposableStack?

729 views

The problem

Question presented to candidate: "A service needs a primary database connection, a replica and a timer at startup. If the second step fails, the first must be closed; if everything succeeds, the caller should own all three and close them together. How would you write that with DisposableStack, and how do you type the pieces?"

What a strong answer should cover:

  • DisposableStack collects cleanup work and is itself Disposable: use(value) registers a disposable, adopt(value, onDispose) wraps a value that has no dispose method, defer(fn) registers a callback; everything runs in reverse order on dispose()
  • The setup pattern: using stack = new DisposableStack(), register each resource right after acquiring it, and on success call stack.move() to transfer ownership out, so a failure part-way rolls back only what was opened
  • AsyncDisposableStack does the same with disposeAsync() / Symbol.asyncDispose, accepts both sync and async disposables, and is used with await using
  • Error aggregation: when several cleanups throw, the errors are chained in SuppressedError objects (error = the later failure, suppressed = the earlier); disposed becomes true even then
  • The types: use<T extends Disposable | null | undefined>(value: T): T and adopt<T>(value: T, onDispose: (value: T) => void): T return the exact type passed in; a composed class holds a stack in a private field and implements Disposable by delegating
  • Runtime support: built in only in newer runtimes (for example Node.js 24 and Chrome 134 per MDN data); otherwise a polyfill, since lib: esnext.disposable only provides types

Clarifying questions expected:

  • Are any of the resources released asynchronously (connections usually are)?
  • Which runtimes must this run on, and is a polyfill acceptable?

Code / implementation expected: Yes β€” an acquire-several-resources function that rolls back on failure and returns a disposable bundle on success.

  • using
  • DisposableStack

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read Β· 11 sections

Run the code

Edit the code and run it here. Each console line with an expected value becomes a test.

TypeScriptDisposableStack: rollback on failure, move() on success
TypeScriptAsyncDisposableStack and SuppressedError aggregation
TypeScriptThe types: use<T>, adopt<T>, and composing a Disposable class

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 68 of 81 in TypeScript

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

How do you use `infer` to build deep `Awaited`, `ReturnType` and `Unwrap` utilities?

Continue