Skip to content

Instantly share code, notes, and snippets.

@ProdigySim
Created April 25, 2022 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ProdigySim/73913e526d12719476582238a3fce2aa to your computer and use it in GitHub Desktop.
Save ProdigySim/73913e526d12719476582238a3fce2aa to your computer and use it in GitHub Desktop.
First pass at enabling inferred names and types on output answers object for enquirer library
diff --git a/module-type-overrides/enquirer.d.ts b/module-type-overrides/enquirer.d.ts
index 27dee4e90..5172f0c5c 100644
--- a/module-type-overrides/enquirer.d.ts
+++ b/module-type-overrides/enquirer.d.ts
@@ -67,6 +67,21 @@ declare namespace Enquirer {
...args: ConstructorParameters<new (...args: any) => T>
) => T;
+ export function prompt<Name extends string, Q extends prompt.Question>(
+ question: Q & { name: Name }
+ ): Promise<Record<Name, AnswerTypeForQuestion<Q>>>;
+ export function prompt<Q extends prompt.Question & { name?: undefined }>(
+ question: Q
+ ): Promise<AnswerTypeForQuestion<Q>>;
+ export function prompt<Name extends string>(
+ question: prompt.CustomQuestion & { name: Name }
+ ): Promise<SpecificAnswers<Name>>;
+ export function prompt<
+ T extends string,
+ Name extends string,
+ Qs extends ReadonlyArray<prompt.Question & { type: T } & { name: Name }>
+ >(questions: [...Qs]): Promise<AnswersForNamedQuestions<[...Qs]>>;
+
export function prompt(question: prompt.Question): Promise<Answers>;
export function prompt(questionFn: (this: Enquirer) => prompt.Question): Promise<Answers>;
export function prompt(
@@ -81,6 +96,9 @@ declare namespace Enquirer {
export namespace prompt {
export function on(type: types.PromptType, handler: (p: Prompt<any>) => void): void;
+ export type NamedQuestion<Name extends string> = Extract<Question, { name: string }> & {
+ name: Name;
+ };
export type Question =
| AutoCompleteQuestion
| BasicAuthQuestion
@@ -102,7 +120,9 @@ declare namespace Enquirer {
| TextQuestion
| ToggleQuestion;
- export type AutoCompleteQuestion = AutoCompleteQuestion.Single | AutoCompleteQuestion.Multiple;
+ export type AutoCompleteQuestion =
+ | AutoCompleteQuestion.Single<any>
+ | AutoCompleteQuestion.Multiple<any>;
export type BasicAuthQuestion = {
type: 'basicauth';
} & BasicAuthQuestionOptions;
@@ -135,25 +155,37 @@ declare namespace Enquirer {
} & internalTypes.CommonQuestion<V, A>;
export namespace AutoCompleteQuestion {
- export type Options = {
+ export type Options<T extends SelectQuestion.Choice[]> = {
type?: 'autocomplete';
- choices: SelectQuestion.Choice[];
+ choices: T;
suggest?: (
input: string,
choices: SelectQuestion.ChoiceOptions[]
) => SelectQuestion.ChoiceOptions[] | Promise<SelectQuestion.ChoiceOptions[]>;
} & types.QuestionBase;
- export type SingleOptions = { multiple?: false } & Type &
- Options &
+ export type SingleOptions<T extends SelectQuestion.Choice[]> = {
+ multiple?: false;
+ } & Options<T> &
types.Initializer<string | number, string> &
types.Formatter<string, string>;
- export type MultipleOptions = { multiple: true } & Type &
- Options &
+ export type MultipleOptions<T extends SelectQuestion.Choice[]> = {
+ multiple: true;
+ } & Options<T> &
types.Initializer<string | number, string[]> &
types.Formatter<string, string[]>;
- export type Single = { type: 'autocomplete' } & SingleOptions;
- export type Multiple = { type: 'autocomplete' } & MultipleOptions;
+ export type Single<T extends SelectQuestion.Choice[]> = {
+ type: 'autocomplete';
+ } & SingleOptions<T>;
+ export type SingleAnswer<Q extends SingleOptions<any>> = SelectQuestion.ChoiceValue<
+ Q['choices'][number]
+ >;
+ export type Multiple<T extends SelectQuestion.Choice[]> = {
+ type: 'autocomplete';
+ } & MultipleOptions<T>;
+ export type MultipleAnswer<Q extends MultipleOptions<any>> = Array<
+ SelectQuestion.ChoiceValue<Q['choices'][number]>
+ >;
}
export type BasicAuthQuestionOptions = {
@@ -335,6 +367,19 @@ declare namespace Enquirer {
*/
value?: string;
};
+ type GetChoiceValue<T extends string | ChoiceOptions | Promise<string | ChoiceOptions>> =
+ T extends string
+ ? T
+ : T extends Promise<infer U>
+ ? U extends { value: infer V }
+ ? infer V
+ : U
+ : T extends { value: infer U }
+ ? U
+ : never;
+ export type ChoiceValue<T extends Choice> = T extends () => infer U
+ ? GetChoiceValue<U>
+ : GetChoiceValue<Exclude<T, Function>>;
}
export type SnippetQuestionOptions = {
@@ -644,6 +689,32 @@ declare namespace Enquirer {
}
export type Answers = Record<string, types.Answer>;
+ export type SpecificAnswers<Names extends string> = Record<Names, types.Answer>;
+
+ type QuestionAnswersMap = {
+ input: string;
+ numeral: number;
+ invisible: string;
+ password: string;
+ list: string[];
+ };
+ export type AnswerTypeForQuestion<Q extends prompt.Question> =
+ Q extends prompt.AutoCompleteQuestion.Single<any>
+ ? prompt.AutoCompleteQuestion.SingleAnswer<Q>
+ : Q extends prompt.AutoCompleteQuestion.Multiple<any>
+ ? prompt.AutoCompleteQuestion.MultipleAnswer<Q>
+ : Q['type'] extends keyof QuestionAnswersMap
+ ? QuestionAnswersMap[Q['type']]
+ : types.Answer;
+ export type AnswerForQuestion<
+ Name extends string,
+ Q extends prompt.Question & { name: Name }
+ > = Record<Name, AnswerTypeForQuestion<Q>>;
+ export type AnswersForNamedQuestions<
+ Qs extends ReadonlyArray<prompt.Question & { name: string }>
+ > = {
+ [K in Qs[number] as K['name']]: AnswerTypeForQuestion<K>;
+ };
export class State {
type: string;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment