<p dir="auto"><code class="notranslate">Deno.readTextFile</code> error is not too descriptive my opinion:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="error: Uncaught NotFound: No such file or directory (os error 2)
..."><pre class="notranslate">error: Uncaught NotFound: No such file or directory (os error 2)
...</pre></div>
<p dir="auto">Maybe it could include a bit more information, like the path it was trying to read?</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="error: Uncaught NotFound: No such file or directory (os error 2): &quot;path/to/file.ts&quot;"><pre class="notranslate">error: Uncaught NotFound: No such file or directory (os error 2): <span class="pl-s"><span class="pl-pds">"</span>path/to/file.ts<span class="pl-pds">"</span></span></pre></div>
<p dir="auto">Hey,</p>
<p dir="auto">Thinking about the I/O stuff made me realize that since we don't have <code class="notranslate">defer</code> in JavaScript and we have exceptions so:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="func main() {
    f, err := os.Open(&quot;/tmp/test.txt&quot;)
    if err != nil {
      return
    }
    defer f.Close();
    n, err := fmt.Fprintln(f, &quot;data&quot;)
    // skip checking n and `err` for brevity but code should
}"><pre class="notranslate"><span class="pl-k">func</span> <span class="pl-en">main</span>() {
    <span class="pl-s1">f</span>, <span class="pl-s1">err</span> <span class="pl-c1">:=</span> <span class="pl-s1">os</span>.<span class="pl-en">Open</span>(<span class="pl-s">"/tmp/test.txt"</span>)
    <span class="pl-k">if</span> <span class="pl-s1">err</span> <span class="pl-c1">!=</span> <span class="pl-c1">nil</span> {
      <span class="pl-k">return</span>
    }
    <span class="pl-k">defer</span> <span class="pl-s1">f</span>.<span class="pl-en">Close</span>();
    <span class="pl-s1">n</span>, <span class="pl-s1">err</span> <span class="pl-c1">:=</span> <span class="pl-s1">fmt</span>.<span class="pl-en">Fprintln</span>(<span class="pl-s1">f</span>, <span class="pl-s">"data"</span>)
    <span class="pl-c">// skip checking n and `err` for brevity but code should</span>
}</pre></div>
<p dir="auto">Could be:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="async function main() {
   const f = await createFile('/tmp/test.txt'); // ignore API bikeshed
   try {
     const n = await f.write(data);
   } finally {
     f.close();
  }
}"><pre class="notranslate"><span class="pl-k">async</span> <span class="pl-k">function</span> <span class="pl-en">main</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-k">const</span> <span class="pl-s1">f</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">createFile</span><span class="pl-kos">(</span><span class="pl-s">'/tmp/test.txt'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// ignore API bikeshed</span>
   <span class="pl-k">try</span> <span class="pl-kos">{</span>
     <span class="pl-k">const</span> <span class="pl-s1">n</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">f</span><span class="pl-kos">.</span><span class="pl-en">write</span><span class="pl-kos">(</span><span class="pl-s1">data</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
   <span class="pl-kos">}</span> <span class="pl-k">finally</span> <span class="pl-kos">{</span>
     <span class="pl-s1">f</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Which unlike <code class="notranslate">defer</code> doesn't really stack up too nicely with multiple files:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="async function main() {
   const f = await createFile('/tmp/test.txt');
   try {
     try {
       const f2 = await createFile('/tmp/test2.txt');
       await f.write('data');
       await f2.write('data'); // or Promise.all and do it concurrently
     } finally {
        f2.close(); // by the way - is this synchronous?
     }
   } finally {
     f.close();
  }
}"><pre class="notranslate"><span class="pl-k">async</span> <span class="pl-k">function</span> <span class="pl-en">main</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-k">const</span> <span class="pl-s1">f</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">createFile</span><span class="pl-kos">(</span><span class="pl-s">'/tmp/test.txt'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
   <span class="pl-k">try</span> <span class="pl-kos">{</span>
     <span class="pl-k">try</span> <span class="pl-kos">{</span>
       <span class="pl-k">const</span> <span class="pl-s1">f2</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">createFile</span><span class="pl-kos">(</span><span class="pl-s">'/tmp/test2.txt'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
       <span class="pl-k">await</span> <span class="pl-s1">f</span><span class="pl-kos">.</span><span class="pl-en">write</span><span class="pl-kos">(</span><span class="pl-s">'data'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
       <span class="pl-k">await</span> <span class="pl-s1">f2</span><span class="pl-kos">.</span><span class="pl-en">write</span><span class="pl-kos">(</span><span class="pl-s">'data'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// or Promise.all and do it concurrently</span>
     <span class="pl-kos">}</span> <span class="pl-k">finally</span> <span class="pl-kos">{</span>
        <span class="pl-s1">f2</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// by the way - is this synchronous?</span>
     <span class="pl-kos">}</span>
   <span class="pl-kos">}</span> <span class="pl-k">finally</span> <span class="pl-kos">{</span>
     <span class="pl-s1">f</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">This sort of code is very hard to write correctly  - especially if resources are acquired concurrently (we don't await before the first createFile finishes to do the second) and some of them fail.</p>
<p dir="auto">We can do other stuff instead for resource management:</p>
<ul dir="auto">
<li>We can expose <a href="https://stackoverflow.com/questions/28915677/what-is-the-promise-disposer-pattern" rel="nofollow">disposers</a> for resource management.</li>
<li>We can expose a <code class="notranslate">using</code> function from deno and have a "real" resource" story.</li>
<li>Something else?</li>
</ul>
<p dir="auto">Here is what the above example looks like with exposing a <code class="notranslate">using</code>:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import { using } from 'deno' 

async function main() {
  await using(createFile('/tmp/test.txt'), createFile('/tmp/test2.txt'), async (test1, test2) =&gt; {
     // when the promise this returns resolves - both files are closed
  }); // can .catch here to handle errors or wrap with try/catch
}"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">using</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'deno'</span> 

<span class="pl-k">async</span> <span class="pl-k">function</span> <span class="pl-en">main</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">await</span> <span class="pl-en">using</span><span class="pl-kos">(</span><span class="pl-en">createFile</span><span class="pl-kos">(</span><span class="pl-s">'/tmp/test.txt'</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">createFile</span><span class="pl-kos">(</span><span class="pl-s">'/tmp/test2.txt'</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-k">async</span> <span class="pl-kos">(</span><span class="pl-s1">test1</span><span class="pl-kos">,</span> <span class="pl-s1">test2</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
     <span class="pl-c">// when the promise this returns resolves - both files are closed</span>
  <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// can .catch here to handle errors or wrap with try/catch</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">We wrote some prior art in bluebird in <a href="http://bluebirdjs.com/docs/api/promise.using.html" rel="nofollow">here</a> - C# also does this with <code class="notranslate">using</code> (I asked before defining <code class="notranslate">using</code> in bluebird and got <a href="https://stackoverflow.com/a/21123756/1348195" rel="nofollow">an interesting perspective from Eric</a>). Python has <code class="notranslate">with</code> and Java has <code class="notranslate">try with resource</code>.</p>
<p dir="auto">Since this is a problem "browser TypeScript" doesn't really have commonly I suspect it will be a few years before a solution might come from TC39 if at all - issues were opened in TypeScript but it was deemed out of scope. Some CCs to get the discussion started:</p>
<ul dir="auto">
<li><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/spion/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/spion">@spion</a> who worked on <code class="notranslate">defer</code> for bluebird coroutines and <code class="notranslate">using</code> with me.</li>
<li><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/littledan/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/littledan">@littledan</a> for a TC39 reference and knowing if there is interest in solving this at a language level.</li>
<li><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/1st1/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/1st1">@1st1</a> who did the work on asynchronous contexts for Python</li>
</ul>
<p dir="auto">We also did some discussion in Node but there is no way I'm aware of for Node to do this nicely that won't be super risky - Deno seems like the perfect candidate for a safer API for resource management.</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/ry/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/ry">@ry</a> if you prefer this as a PR with a concrete proposal for either approach let me know. Alternatively if you prefer the discussion to happen at a later future point let me know.</p>