🦕

Denoで一時ディレクトリを自動削除するには

に公開

Deno では、Deno.makeTempDirDeno.makeTempDirSync のような一時ディレクトリを作成する関数が提供されています。しかし、これらの関数は一時ディレクトリを削除する処理を自動的に行ってくれません。そのため、開発者は適切なエラーハンドリングのもと一時ディレクトリを削除する処理を別途組み込む必要があります。このような処理は try/finally パターンを使って実装することが一般的ですが、コードが冗長になりがちです。

この記事では、using 宣言を利用することで、自動的に削除される一時ディレクトリを実現する方法を紹介します。

前提条件

  • TypeScript 5.2 以降
  • Deno v2.4.3 で動作確認

using 宣言

using 宣言は、try/finally パターンを簡潔に書くことができる構文です。例えば、以下のコードを考えます。

try {
    console.log("start");
    console.log("do something");
} finally {
    console.log("end");
}

using 宣言を使うと、上記のコードは次のように書き換えることができます。

const printLog = (): Disposable => {
    console.log("start")
    return {
        [Symbol.dispose]() {
            console.log("end");
        }
    };
}

{
    using x = printLog()
    console.log("do something");
    // x が破棄されるときに Symbol.dispose で定義した処理が呼ばれる
}

printLog の返す値には、Symbol.dispose メソッドが実装されており、using ブロックを抜けると自動的にそのメソッドが呼び出されます。このメソッドは、処理中にエラーが発生した場合でも確実に呼び出されるため、リソースの解放や片付けを行うのに非常に便利です。

自動的に削除される一時ディレクトリの作成

一時ディレクトリを削除する処理をSymbol.dispose メソッドに組み込むことで、スコープを抜けると同時に自動的に削除される一時ディレクトリを作成することができます。例えば、以下のように実装できます。

const usingTempDirSync = (): Disposable & { path: string } => {
  const tempDir = Deno.makeTempDirSync();
  return {
    path: tempDir,
    [Symbol.dispose]() {
      Deno.removeSync(tempDir, { recursive: true });
    },
  }
};

// 使い方
{
  using tempDir = usingTempDirSync();
  console.log(`一時ディレクトリのパス: ${tempDir.path}`);
} // ここで Symbol.dispose が呼ばれ、一時ディレクトリが削除される

また、Symbol.asyncDispose メソッドを使うことで、非同期処理での実装も可能です。この場合は、以下のような実装になります。

const usingTempDir = async (): Promise<AsyncDisposable & { path: string }> => {
  const tempDir = await Deno.makeTempDir();
  return {
    path: tempDir,
    async [Symbol.asyncDispose]() {
      await Deno.remove(tempDir, { recursive: true });
    },
  };
};

// 使用例。await を2回使う必要があります。
await using tempDir = await usingTempDir();

まとめ

using 宣言を利用することで、一時ディレクトリを自動的に削除することができました。これにより、try/finally パターンを使う際の冗長なコードを避け、より簡潔で読みやすいコードを書くことが可能になります。特に、一時ディレクトリを何回も作成する必要がある場合には、かなり有用だと思います。

参考リンク

Discussion