Open4

JavaScript (Deno) で `cause` がチェーンされた Error をいい感じにテキスト表現で取得したい場合、`Deno.inspect` が便利

magurotunamagurotuna

以下のようなコードがあるとする

class MyError extends Error {
  constructor(cause: unknown) {
    super("myerror!");
    this.name = "MyError";
    this.cause = cause;
  }
}

function throwError() {
  const e1 = new Error("e1");
  const e2 = new Error("e2", { cause: e1 });
  const myError = new MyError(e2);
  throw myError;
}

try {
  throwError();
} catch (e: unknown) {
  console.log(e);
}

ES2022で追加された cause プロパティを使って、3段階にネストされた Error を作ってthrowし、それをキャッチしている。

cause についての参考記事:
https://zenn.dev/pixiv/articles/bb123b2f50cdab#es2022-error-cause

これをDeno (v2.1.5) で実行すると、以下のような出力になる

❯ deno run error_chain.ts
MyError: myerror!
    at throwError (file:///private/tmp/error_chain.ts:12:19)
    at file:///private/tmp/error_chain.ts:17:3
Caused by Error: e2
    at throwError (file:///private/tmp/error_chain.ts:11:14)
    at file:///private/tmp/error_chain.ts:17:3
Caused by Error: e1
    at throwError (file:///private/tmp/error_chain.ts:10:14)
    at file:///private/tmp/error_chain.ts:17:3 {
  name: "MyError"
}

MyError -> e2 -> e1 というエラーの連鎖が正しく保持されている。

magurotunamagurotuna

一方、console.log(e) ではなく console.log(e.toString()) にすると、出力が変わる

❯ deno run error_chain.ts
MyError: myerror!

情報量が足りない…
console.log(e) のときと同じリッチな情報を文字列として得たい場合、どうすればよいか?

magurotunamagurotuna

Deno.inspect というAPIがある

https://docs.deno.com/api/deno/~/Deno.inspect

Converts the input into a string that has the same format as printed by console.log().

とあるように、引数で与えられた入力を、console.log に渡したときと同じフォーマットの文字列に変換して返してくれる。

try {
  throwError();
} catch (e: unknown) {
  const s = Deno.inspect(e);
  await Deno.stdout.write(new TextEncoder().encode(s));
}

のようにすれば、console.log(e) したときと同じ文字列が得られていることが確認できる[1]:

❯ deno run error_chain.ts
MyError: myerror!
    at throwError (file:///private/tmp/error_chain.mts:14:19)
    at file:///private/tmp/error_chain.mts:19:3
Caused by Error: e2
    at throwError (file:///private/tmp/error_chain.mts:13:14)
    at file:///private/tmp/error_chain.mts:19:3
Caused by Error: e1
    at throwError (file:///private/tmp/error_chain.mts:12:14)
    at file:///private/tmp/error_chain.mts:19:3 {
  name: "MyError"
}
脚注
  1. 標準出力への出力にconsole.logを使っていないのは、console.logによるフォーマットが効いているのではなく、Deno.inspectによるフォーマットが行われていることを明確にするため ↩︎