inquirer の使い方

A collection of common interactive command line user interfaces.

v13.3.2/週MITCLI
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

Inquirer.js の使い方 — Node.js 対話型CLIプロンプトの定番ライブラリ

一言でいうと

Inquirer.js は、Node.js のコマンドラインアプリケーションで対話型のユーザー入力(テキスト入力、選択リスト、チェックボックス、確認ダイアログなど)を簡単に実装するためのライブラリです。CLIツールやスキャフォールディングツールの質問フローを構築する際のデファクトスタンダードです。

⚠️ 重要: inquirer(v13系)はレガシー版です。新規プロジェクトでは後継の @inquirer/prompts の採用が推奨されています。本記事では既存プロジェクトでの利用や移行前の理解を目的に inquirer を解説します。

どんな時に使う?

  • CLIツールの初期設定ウィザード — プロジェクトの init コマンドで、名前・テンプレート・オプションなどを対話的に聞き取る
  • スキャフォールディング/コード生成 — Yeoman のようにテンプレートからファイルを生成する際、ユーザーの選択に応じて出力を分岐させる
  • デプロイ・運用スクリプトの確認 — 危険な操作の前に「本当に実行しますか?」と確認を挟む

インストール

# npm
npm install inquirer

# yarn
yarn add inquirer

# pnpm
pnpm add inquirer

注意: Inquirer v13 は ESM (ES Modules) 専用です。package.json"type": "module" を設定するか、.mjs 拡張子を使用してください。

基本的な使い方

最も一般的なパターンは、質問オブジェクトの配列を prompt() に渡し、回答をまとめて受け取る方法です。

import inquirer from 'inquirer';

interface ProjectAnswers {
  projectName: string;
  language: 'TypeScript' | 'JavaScript';
  useEslint: boolean;
}

const answers = await inquirer.prompt<ProjectAnswers>([
  {
    type: 'input',
    name: 'projectName',
    message: 'プロジェクト名を入力してください:',
    default: 'my-app',
    validate: (input: string) => {
      if (/^[a-z0-9-]+$/.test(input)) return true;
      return '英小文字・数字・ハイフンのみ使用できます';
    },
  },
  {
    type: 'list',
    name: 'language',
    message: '使用する言語を選択してください:',
    choices: ['TypeScript', 'JavaScript'],
  },
  {
    type: 'confirm',
    name: 'useEslint',
    message: 'ESLint を導入しますか?',
    default: true,
  },
]);

console.log(`プロジェクト "${answers.projectName}" を ${answers.language} で作成します`);
console.log(`ESLint: ${answers.useEslint ? '有効' : '無効'}`);

よく使うAPI・プロンプトタイプの使い方

1. input — テキスト入力

const { username } = await inquirer.prompt([
  {
    type: 'input',
    name: 'username',
    message: 'ユーザー名:',
    default: 'admin',
    transformer: (input: string) => {
      // 表示時のみ加工(回答値には影響しない)
      return input.toLowerCase();
    },
  },
]);

2. list / rawlist — 単一選択

const { region } = await inquirer.prompt([
  {
    type: 'list',
    name: 'region',
    message: 'デプロイ先リージョンを選択:',
    choices: [
      { name: '東京 (ap-northeast-1)', value: 'ap-northeast-1' },
      { name: '大阪 (ap-northeast-3)', value: 'ap-northeast-3' },
      { name: 'バージニア (us-east-1)', value: 'us-east-1' },
      new inquirer.Separator('--- 以下は実験的 ---'),
      { name: 'シンガポール (ap-southeast-1)', value: 'ap-southeast-1' },
    ],
    pageSize: 10,
  },
]);
// region: "ap-northeast-1" など

3. checkbox — 複数選択

const { features } = await inquirer.prompt([
  {
    type: 'checkbox',
    name: 'features',
    message: '導入する機能を選択してください:',
    choices: [
      { name: 'Router', value: 'router', checked: true },
      { name: 'State Management (Pinia)', value: 'pinia' },
      { name: 'Unit Testing (Vitest)', value: 'vitest' },
      { name: 'E2E Testing (Playwright)', value: 'playwright' },
    ],
    validate: (answer: string[]) => {
      if (answer.length === 0) return '少なくとも1つ選択してください';
      return true;
    },
  },
]);
// features: ["router", "pinia"] など

4. confirm — Yes/No 確認

const { proceed } = await inquirer.prompt([
  {
    type: 'confirm',
    name: 'proceed',
    message: '本番環境にデプロイします。続行しますか?',
    default: false,
  },
]);

if (!proceed) {
  console.log('キャンセルしました');
  process.exit(0);
}

5. password — パスワード入力

const { apiKey } = await inquirer.prompt([
  {
    type: 'password',
    name: 'apiKey',
    message: 'APIキーを入力してください:',
    mask: '*', // 入力文字を * で表示(省略すると非表示)
    validate: (input: string) => {
      if (input.length < 10) return 'APIキーは10文字以上です';
      return true;
    },
  },
]);

補足: when による条件分岐と filter による値変換

const answers = await inquirer.prompt([
  {
    type: 'confirm',
    name: 'useDatabase',
    message: 'データベースを使用しますか?',
    default: false,
  },
  {
    type: 'list',
    name: 'dbType',
    message: 'データベースの種類:',
    choices: ['PostgreSQL', 'MySQL', 'SQLite'],
    // useDatabase が true の場合のみ表示
    when: (answers) => answers.useDatabase,
  },
  {
    type: 'input',
    name: 'dbPort',
    message: 'ポート番号:',
    when: (answers) => answers.useDatabase,
    filter: (input: string) => parseInt(input, 10), // 文字列を数値に変換
    validate: (input: string) => {
      const port = parseInt(input, 10);
      if (isNaN(port) || port < 1 || port > 65535) return '有効なポート番号を入力してください';
      return true;
    },
  },
]);

類似パッケージとの比較

特徴inquirer (v13)@inquirer/promptspromptsenquirer
メンテナンス状況メンテナンスのみ活発に開発中低頻度低頻度
API スタイル質問配列を一括渡し個別関数呼び出し質問配列を一括渡し質問配列を一括渡し
ESM 対応❌ (CJS)
TypeScript 型定義同梱同梱@types/prompts@types/enquirer
バンドルサイズ大きめ(RxJS依存)軽量軽量中程度
プラグイン拡張registerPrompt
推奨度(2025年)既存プロジェクト向け新規プロジェクト推奨軽量志向にメンテ不安

結論: 新規プロジェクトでは @inquirer/prompts を選択するのがベストです。inquirer からの移行も段階的に行えます。

注意点・Tips

1. ESM 必須(v13以降)

// package.json
{
  "type": "module"  // これがないと import inquirer from 'inquirer' が失敗する
}

CommonJS (require) で使いたい場合は inquirer@^8 系を使うか、動的 import() を利用してください。

2. TTY でない環境ではエラーになる

CI/CD パイプラインや、stdin がパイプされている環境では isTtyError が発生します。非対話環境ではデフォルト値にフォールバックする設計にしましょう。

try {
  const answers = await inquirer.prompt(questions);
} catch (error: any) {
  if (error.isTtyError) {
    console.log('非対話環境のため、デフォルト設定を使用します');
    // デフォルト値でフォールバック
  } else {
    throw error;
  }
}

3. name にドット区切りを使うとネストされる

const answers = await inquirer.prompt([
  { type: 'input', name: 'db.host', message: 'DB Host:' },
  { type: 'input', name: 'db.port', message: 'DB Port:' },
]);
// answers = { db: { host: "localhost", port: "5432" } }

便利ですが、意図せずドットを含む名前を使うとハマるので注意してください。

4. 既存回答のスキップ

prompt() の第2引数に回答オブジェクトを渡すと、該当する質問をスキップできます。CLI引数で渡された値を事前にセットしておくパターンに便利です。

import { parseArgs } from 'node:util';

const { values } = parseArgs({
  options: { name: { type: 'string' } },
});

// --name が指定済みなら projectName の質問をスキップ
const answers = await inquirer.prompt(
  [{ type: 'input', name: 'projectName', message: 'プロジェクト名:' }],
  { projectName: values.name }, // 事前回答
);

5. @inquirer/prompts への段階的移行

両パッケージは同時に使えるため、新しい質問から順に移行できます。

// 旧 API(inquirer)
import inquirer from 'inquirer';

// 新 API(@inquirer/prompts)— 個別関数で呼び出す
import { input, select, confirm } from '@inquirer/prompts';

const name = await input({ message: 'プロジェクト名:' });
const lang = await select({
  message: '言語:',
  choices: [
    { name: 'TypeScript', value: 'ts' },
    { name: 'JavaScript', value: 'js' },
  ],
});

まとめ

Inquirer.js は、Node.js の対話型 CLI を構築するための成熟したライブラリで、inputlistcheckboxconfirmpassword など豊富なプロンプトタイプと、validatewhenfilter による柔軟な制御を提供します。v13 はレガシー版としてメンテナンスされている状態なので、新規プロジェクトでは後継の @inquirer/prompts を、既存プロジェクトでは段階的な移行を検討してください。