Auto-cleanup with "[await] using" (new Ecmascript feature)

TL;DR: this is the code you can start writing after enabling this new feature

  using reader = stream.getReader();
  const { value, done } =;
} // 'reader' is disposed

If you

a) Build meteor with Typescript
b) Think you spend too much time writing try/finally blocks where the finally part cleans up resources (closing file handles etc)

then this article is for you.

With Typescript 5.2 comes support for Ecmascript Explicit Resource Management and here’s how you enable it in your project.

  • Ensure you use refapp:meteor-typescript and not Meteor’s limited typescript support
  • Use at least version 0.3.17 of refapp:meteor-typescript
  • Ensure you have the latest version of tslib in node_modules (install using npm/yarn)
  • Ensure your tsconfig.json contains configuration that includes at least
"target": "ES2022",
"lib": ["ES2022",  "esnext.disposable"],
  • Add a polyfill (both client and server) for the new symbols and classes and load it early (in your “main” files and/or early in your dependencies. I use disposablestack
import "disposablestack/auto";

Until VSCode ships with Typescript 5.2 you also have to add typescript 5.2 to your node_modules and configure vscode to use your local version instead of the bundled one (for IntelliSense to work correctly) but other than that, you are all set at this point.

Example code:

In our tests, we have a helper method that sets up a new tenant. I added a cleanup method to it.

export async function createCompanyWithUserAsync(
  email: string,
...) {
 ... // code that creates a "Company" in the db
  return {
     * So that the caller can use "await using" and get auto-cleanup
    [Symbol.asyncDispose]: async () => {
      await DeleteCompany.testInvokeAsync(adminConn, companyId);

and then I could simply change my old try/finally code into

      await using tmpCompany = await createCompanyWithUserAsync(adminUserEmail);

and not have to think anymore about keeping the cleanup code up to date