TypeScript & JavaScript · T296

What does using actually clean up?

Using calls a resource’s Symbol.dispose method when execution leaves its block. The ES2020 output adds resource helpers and a try/finally structure.

The important bit
The demo records work, dispose, done and also checks cleanup on a thrown error. This is synchronous resource disposal, not garbage collection. Compatible resources and runtime support are required; ordinary close APIs can use manual try/finally.

Understand it. Then fix it.

It calls a method when the block ends.

No. Using calls a resource’s cleanup method when execution leaves the block. That method lives under Symbol dot dispose, a special property key. Demo resource: records cleanup, opens no real file.

const resource = {
  [Symbol.dispose]() {
    events.push("dispose");
  }
};

Return does not skip cleanup.

Here, the function records work and returns done. Before the caller gets done, using calls the cleanup method. The order is work, dispose, done. events starts as an empty array.

function job() {
  using r = resource;
  events.push("work");
  return "done";
}
events.push(job());

The compiler adds helpers and finally.

For this target, the compiler adds helper functions and a try finally structure. Finally runs on normal exit, return, or an error. The helpers track the resource and call cleanup. Helper bodies and error handling omitted here.

// Emitted structure, shortened
try {
  // Register resource and do work
} finally {
  __disposeResources(env_1);
}

No dispose method? Use try finally.

If your resource only has close, use try finally yourself. Using needs a compatible resource and runtime support for Symbol dot dispose. Illustrative file API · synchronous cleanup.

const file = openFile();
try {
  return read(file);
} finally {
  file.close();
}

Cleanup is not garbage collection.

Cleanup releases a resource at a known point. Garbage collection manages unreachable memory. These are different jobs. Async cleanup needs a separate approach. await using is a separate lesson.

Code blocks are teaching excerpts. Keep the surrounding error handling and application requirements.

Save the code excerpts ↓
Read the full transcript

What does using actually clean up? Does it just ask the garbage collector nicely? No. Using calls a resource’s cleanup method when execution leaves the block. That method lives under Symbol dot dispose, a special property key. Here, the function records work and returns done. Before the caller gets done, using calls the cleanup method. The order is work, dispose, done. So where did the extra JavaScript come from? For this target, the compiler adds helper functions and a try finally structure. Finally runs on normal exit, return, or an error. The helpers track the resource and call cleanup. If your resource only has close, use try finally yourself. Using needs a compatible resource and runtime support for Symbol dot dispose. Cleanup releases a resource at a known point. Garbage collection manages unreachable memory. These are different jobs. Async cleanup needs a separate approach. The compiler cleans up after me. My apartment would like this feature.

Go to the source