Inquirer.js:构建交互式命令行问答

FreeGuideOnline 最新 2026-06-18

Inquirer.js 入门与实战:构建交互式命令行问答

Inquirer.js 是 Node.js 生态中最流行的交互式命令行界面库,它能让你用几行代码就创建出美观、易用的问答流程,收集用户输入。无论是构建 CLI 工具、自动化脚本还是项目脚手架,Inquirer 都能大幅提升用户体验。

为什么选择 Inquirer?

  • 丰富的交互类型:输入框、多选、确认、列表、密码等,覆盖绝大多数场景。
  • 强大的校验与转换:内置验证、过滤、数据转换机制,确保输入合法。
  • 简明的异步 API:基于 Promise,易于与现代异步流程集成。
  • 高度可定制:支持动态问题、条件显示、自定义前缀与主题。
  • 庞大的社区:GitHub 24k+ Stars,Vue CLI、Create React App 等知名项目都在使用。

安装与第一个问答

确保你的开发环境已安装 Node.js(12+),然后新建项目或直接在现有项目中安装:

npm install inquirer

创建一个 ask.js 文件,写入以下代码:

import inquirer from 'inquirer';

const questions = [
  {
    type: 'input',
    name: 'username',
    message: '请输入你的名字:',
    default: '游客',
  },
];

inquirer.prompt(questions).then((answers) => {
  console.log(`你好,${answers.username}!`);
});

运行 node ask.js,你会看到一个带前缀的问句,输入后按回车即可。这就是 Inquirer 的核心工作流:定义问题数组,调用 prompt 方法,返回包含答案的对象。

问题对象基础

每个问题都是一个包含以下字段的对象(部分字段可选):

字段 类型 说明
type string 问题类型,例如 'input', 'list', 'checkbox'
name string 答案在结果对象中的键名
message string | Function 显示给用户的提示信息,支持动态生成
default any | Function 默认值,按回车直接使用
choices Array | Function 用于 list, rawlist, expand, checkbox 等类型
validate Function 输入验证函数
filter Function 答案过滤/转换函数
when boolean | Function 条件判断,决定该问题是否展示

问题类型详解

Inquirer 提供了多种内置类型,下面逐一介绍并给出示例。

1. input —— 文本输入

最基础的类型,用户可自由输入字符串。

{
  type: 'input',
  name: 'email',
  message: '请输入邮箱:',
  validate(value) {
    const pass = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
    return pass || '请输入有效的邮箱地址!';
  },
}

2. number —— 数字输入

接受数字,自动转换类型,可配置边界。

{
  type: 'number',
  name: 'age',
  message: '你的年龄是?',
  validate(value) {
    return (value >= 0 && value <= 120) || '年龄不合法';
  },
  default: 18,
}

3. confirm —— 确认询问

返回布尔值,常用于确认操作。

{
  type: 'confirm',
  name: 'continue',
  message: '是否继续执行?',
  default: true,
}

4. list —— 单选列表

用户通过上下箭头选择一项,返回选中值或对象。

{
  type: 'list',
  name: 'framework',
  message: '选择前端框架:',
  choices: [
    { name: 'React', value: 'react' },
    { name: 'Vue', value: 'vue' },
    { name: 'Angular', value: 'angular' },
    new inquirer.Separator(), // 分隔线
    { name: '退出', value: 'quit' },
  ],
}

说明choices 可以是字符串数组,也可以是包含 name(显示文字)和 value(实际值)的对象数组。Separator 用于添加不可选的分隔符。

5. rawlist —— 索引列表

list 类似,但显示为有序编号列表,用户输入数字选择。

{
  type: 'rawlist',
  name: 'editor',
  message: '偏好编辑器:',
  choices: ['VS Code', 'WebStorm', 'Sublime Text'],
}

6. expand —— 展开式菜单

展示一组快捷键选项,按对应字符选择。

{
  type: 'expand',
  name: 'theme',
  message: '选择主题:',
  choices: [
    { key: 'd', name: 'Dark', value: 'dark' },
    { key: 'l', name: 'Light', value: 'light' },
    { key: 'c', name: 'Custom', value: 'custom' },
  ],
}

7. checkbox —— 多选列表

用户可以勾选多个选项,返回所选值的数组。

{
  type: 'checkbox',
  name: 'features',
  message: '选择需要的特性:',
  choices: [
    { name: 'TypeScript', checked: true },
    { name: 'ESLint' },
    { name: 'Prettier', checked: true },
  ],
}

checked: true 可以使选项默认打勾。

8. password —— 密码输入

输入内容会被隐藏,常用于敏感信息。

{
  type: 'password',
  name: 'token',
  message: '请输入 API Token:',
  mask: '*', // 可自定义掩码
}

9. editor —— 编辑器输入

在外部编辑器(如 vim、nano)中打开临时文件供用户编辑。

{
  type: 'editor',
  name: 'bio',
  message: '编辑你的简介:',
}

注意:需要系统具备默认编辑器或通过 EDITOR 环境变量指定。

验证、过滤与转换

良好的 CLI 工具必须保证数据质量,Inquirer 在问题定义中提供了三个核心函数:

  • validate:接收用户输入,返回 true 或错误信息字符串。
  • filter:接收原始输入,返回处理后的值,不影响最终答案的类型。
  • transformer:仅影响界面显示,不影响最终答案,可实时预处理展示内容。

示例:强制输入大写并验证长度。

{
  type: 'input',
  name: 'code',
  message: '输入代码(至少6位):',
  filter(input) {
    return input.toUpperCase();
  },
  validate(input) {
    return input.length >= 6 || '代码长度至少6位';
  },
}

动态行为:when 与函数属性

很多属性可以是一个函数,根据之前的答案动态决定。

基于答案的条件显示

const questions = [
  {
    type: 'confirm',
    name: 'wantTypes',
    message: '需要 TypeScript 支持吗?',
  },
  {
    type: 'list',
    name: 'tsTarget',
    message: '选择编译目标:',
    choices: ['ES6', 'ESNext'],
    when(answers) {
      return answers.wantTypes; // 仅当用户选择 “是” 时才显示
    },
  },
];

动态生成默认值或选项

{
  type: 'list',
  name: 'packageManager',
  message: '选择包管理器:',
  choices: ['npm', 'yarn', 'pnpm'],
  default(answers) {
    // 如果用户之前选择了 Vue,则默认使用 yarn
    return answers.framework === 'vue' ? 'yarn' : 'npm';
  },
}

组合复杂流程

实际项目中,单个 prompt 往往不够,需要多步骤、循环或条件分支。你可以将多次 prompt 串联。

async function ask() {
  const { env } = await inquirer.prompt({
    type: 'list',
    name: 'env',
    message: '部署环境:',
    choices: ['开发', '测试', '生产'],
  });

  if (env === '生产') {
    const { confirm } = await inquirer.prompt({
      type: 'confirm',
      name: 'confirm',
      message: '⚠️  即将部署到生产环境,确认?',
    });
    if (!confirm) {
      console.log('已取消');
      return;
    }
  }

  const details = await inquirer.prompt([
    { type: 'input', name: 'version', message: '版本号:' },
    { type: 'password', name: 'token', message: '部署 Token:' },
  ]);

  console.log('最终配置:', { env, ...details });
}

ask();

美化输出:前缀、分隔符与样式

  • 自定义前缀:在 prompt 时传入 prefix 选项。
  • 主题定制:通过 new inquirer.ui.Prompt(stream, options) 深入控制,或借助 @inquirer/select 等新模块。
inquirer.prompt(questions, { prefix: '🚀' });

实战:构建一个项目初始化器

我们将模拟一个脚手架工具,引导用户选择模板、配置选项并生成项目。

import inquirer from 'inquirer';

async function initProject() {
  const answers = await inquirer.prompt([
    {
      type: 'input',
      name: 'projectName',
      message: '项目名称:',
      default: 'my-app',
      validate: (v) => v.length > 0 || '名称不能为空',
    },
    {
      type: 'list',
      name: 'template',
      message: '选择模板:',
      choices: [
        { name: 'Vue 3 + Vite', value: 'vue-vite' },
        { name: 'React + Vite', value: 'react-vite' },
        { name: 'Node 后端', value: 'node-server' },
      ],
    },
    {
      type: 'checkbox',
      name: 'features',
      message: '附加特性:',
      choices: [
        { name: 'TypeScript', value: 'ts' },
        { name: 'ESLint + Prettier', value: 'lint' },
        { name: '单元测试 (Vitest)', value: 'test' },
      ],
    },
    {
      type: 'input',
      name: 'author',
      message: '作者:',
      default: 'dev',
    },
    {
      type: 'confirm',
      name: 'install',
      message: '立即安装依赖?',
      default: true,
    },
  ]);

  // 模拟生成操作
  console.log('\n📁 项目配置已生成:');
  console.log(JSON.stringify(answers, null, 2));
}

initProject();

至此,一个具备输入、选择、多选和确认的标准 CLI 向导就完成了。

进阶提示

  • 搜索选择:使用 @inquirer/select(内置搜索)或 inquirer-search-list 在长列表中快速定位。
  • 文件路径补全:通过 inquirer-file-tree-selection-prompt 等插件实现。
  • 无交互模式:用 inquirer--silent 或传入预设答案,方便测试。
  • 错误处理prompt 返回的 Promise 可以使用 .catch 捕获用户中断(Ctrl+C)。

总结

Inquirer.js 让命令行交互变得简单而强大。无论是简单的参数收集还是复杂的多步向导,你都可以通过组合问题类型、运用校验和条件逻辑来实现。掌握了这些技巧,你的 Node.js CLI 工具将具备专业级的用户体验。

参考资源