Oteto Blogのロゴ

【Node.js】execSyncの返り値からstderrを取得してエラーハンドリングしたい

困ったこと

Node.jsのchild_process.execSync()は他のexec()spawnSync()などと違いstderrを直接返してくれるわけではない。

import { execSync } from 'child_process';

function myCommand(command: string): string {
  try {
    return execSync(command).toString();
  } catch (e: unknown) {
    if (e instanceof Error) {
      console.error(e.stderr.toString()); // Property 'stderr' does not exist on type 'Error'
    }
    throw e;
  }
}

そのため例外処理の際にErrorオブジェクトから取得することになるが、もちろんそのままでは取得させてくれない。

if (e instanceof Error) {
if (e instanceof ExecException) { // 'ExecException' only refers to a type, but is being used as a value here.
  console.error(e.stderr.toString());
}

更に組み込みのExecExceptionも型情報しか提供されてないため利用できない。

解決法

function hasStderr(err: any): err is { stderr: Buffer } {
  return !!err.stderr;
}
if (e instanceof Error) {
if (hasStderr(e)) {
  console.error(e.stderr.toString());
}

やや苦肉の策ではあるがユーザ定義型ガードを使う。