SBoudrias / Inquirer.js

A collection of common interactive command line user interfaces.
MIT License
20.05k stars 1.3k forks source link

Easier API for one-shot questions #727

Closed felixfbecker closed 6 years ago

felixfbecker commented 6 years ago

In my usage of inquirer, I've found that most prompts only ask a single question, i.e. I call prompt() for every question individually. This is because the logic of when to ask which question is complicated and better expressed with if statements than with the when option.

Using the when option is also not easy to make type safe, because prompt() returns a question object with a key for every question, but there is no way to statically analyse which keys will be present or not. With if statements and individual calls to prompt(), TypeScript (or Flow) can know for sure which values are there.

However, using the current prompt() API is incredibly cumbersome for single questions, especially when using TypeScript:

const { packageName } = await prompt<{ packageName: string }>({
    name: 'packageName',
    message: 'What should the name of the package be?',
})

As you can see, I have to define the name three times (two times if using JS):

  1. In options.name
  2. In the type parameter
  3. When destructuring

I understand that the syntax for "bulk" asking questions was maybe convenient when Node was all callback based to avoid callback hell, but we now have Promise support in inquirer and async/await since Node 8.

Could we have an API for asking single questions? Something like

const packageName = await promptOne({ message: 'What should the name of the package be?' })

Way less boilerplate, and working type inference.

SBoudrias commented 6 years ago

Hey @felixfbecker thanks for opening this issue.

I've already though about this as part of a refactor I want to see in Inquirer. It's not been progressing very fast right now, but if you're willing to, help would be welcomed. You can learn more about the refactor over here https://github.com/SBoudrias/Inquirer.js/issues/692

I'll close this issue as I'm not really open to release a major breaking changes without major changes to the core library.

mnpenner commented 5 years ago

I'm using this for now:

async function ask(question) {
    return (await Inquirer.prompt({...question,name:'_'}))._
}