@inquirer/prompts を使った CLI ツールで、ユーザーが Ctrl+C でプロンプトを中断すると、以下のような例外のスタックトレースが表示されてしまう。これはユーザー体験として良くない。
ExitPromptError: User force closed the prompt with 0 null
at /path/to/node_modules/@inquirer/core/dist/esm/index.js:123:45
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
...@inquirer/prompts では、ユーザーが Ctrl+C を押すとプロンプトの Promise が reject される。この際に ExitPromptError という名前のエラーがスローされる。
これは意図的な設計で、アプリケーションがクリーンアップ処理を行えるようにするためのもの。しかし、適切にハンドリングしないとスタックトレースがそのまま表示されてしまう。
グローバルな uncaughtException ハンドラを設定して、ExitPromptError の場合はユーザーフレンドリーなメッセージを表示する。
instanceof は使わないExitPromptError クラスを直接インポートして instanceof でチェックする方法は、パッケージの構造上うまく動作しないケースがある。
代わりに error.name === 'ExitPromptError' でチェックするのが推奨されている。
/**
* プロンプトがキャンセルされたエラーかどうかを判定する
*/
function isPromptCancelled(error: unknown): boolean {
return error instanceof Error && error.name === 'ExitPromptError';
}
// グローバルエラーハンドラ
process.on('uncaughtException', (error) => {
if (isPromptCancelled(error)) {
console.log('\nCancelled.');
process.exit(0);
}
throw error;
});これだけで、CLI のどこで Ctrl+C が押されても適切に処理される。
修正前:
? Enter title › ^C
ExitPromptError: User force closed the prompt with 0 null
at /path/to/node_modules/@inquirer/core/dist/esm/index.js:123:45
...修正後:
? Enter title › ^C
Cancelled.