Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: export Question and Answers #1559

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mshima
Copy link
Contributor

@mshima mshima commented Sep 18, 2024

Related to #1527.

Copy link

codecov bot commented Sep 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Please upload report for BASE (main@bd45397). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1559   +/-   ##
=======================================
  Coverage        ?   98.03%           
=======================================
  Files           ?       39           
  Lines           ?     2389           
  Branches        ?      644           
=======================================
  Hits            ?     2342           
  Misses          ?       40           
  Partials        ?        7           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -47,7 +47,7 @@ export interface QuestionMap {
type KeyValueOrAsyncGetterFunction<T, k extends string, A extends Answers> =
T extends Record<string, any> ? T[k] | AsyncGetterFunction<T[k], A> : never;

export type AnyQuestion<A extends Answers, Type extends string = string> = {
export type AnyQuestion<A extends Answers = Answers, Type extends string = string> = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to rename it to match what @type/inquirer used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnyQuestion is been exported as Question.
Answers matches too.

Question has a more advanced type called DistinctQuestion which is the current BuiltInQuestion with name property.
I prefer BuiltInQuestion over DistinctQuestion.

Copy link

@DelliriumX DelliriumX Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DistinctQuestion was used in @types/inquirer. I honestly do not care so long as we get that type(BuiltInQuestion or DistinctQuestion, wherever the decision lands), but if its all the same, i'd use the same one that was used before for the sake of "easier" transition.

Comment on lines 83 to 110
describe('exported types', () => {
type Answers = import('./src/index.mjs').Answers;
type Question = import('./src/index.mjs').Question;

it('Question type is not any', () => {
expectTypeOf({}).not.toMatchTypeOf<Question>();
});

it('exported Question type requires type, name and message', () => {
expectTypeOf({
type: 'stub',
name: 'q1',
message: 'message',
}).toMatchTypeOf<Question>();
expectTypeOf({ name: 'q1', message: 'message' }).not.toMatchTypeOf<Question>();
expectTypeOf({ type: 'stub', message: 'message' }).not.toMatchTypeOf<Question>();
expectTypeOf({ type: 'stub', name: 'q1' }).not.toMatchTypeOf<Question>();
});

it('exported Answers type is not any', () => {
expectTypeOf(false).not.toMatchTypeOf<Answers>();
});

it('exported Answers type matches any object', () => {
expectTypeOf({}).toMatchTypeOf<Answers>();
expectTypeOf({ foo: 'bar' }).toMatchTypeOf<Answers>();
});
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In term of test, I was more thinking along the line of ensuring proper behavior when used; e.g

it('Question[] infers the right return type', async () => {
  const questions: Question[] = [
    { ... },
  ];

  const answers = await inquirer.prompt(questions);

  expectTypeOf(answers).toMatchTypeOf<{ foo: any; bar: any; }>();
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure it's possible.
prompt() function types are too complex to be reused.
Types are internal to the prompt function.

I think we should expose a generic type.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I follow - I'm just talking of testing the behavior, not changing the type interface (unless it'd become necessary.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returned type of Question will alway be Record<string, any>.

Copy link
Owner

@SBoudrias SBoudrias Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this is what I thought would happen. That's what I was telling @DelliriumX over #1527 (comment) - but they seemed pretty sure of themselves 🤷🏻 Figured I was missing something.

So yeah then exporting the types (as-is) does break type inference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I am pretty sure answers type inference does not exist in v9 types.
  • in yeoman-generator there is no type inference and I don’t plan to add it.

Exported types is just for easy custom apis:

  • if any type inference is needed it should use the function type.
  • It’s not even possible for inquirer to create the function type, maybe it’s not possible to extract it and keep type inference.

Plain Question/Answers and maybe BuiltInQuestion should be enough to replace @types/inquirer.

Copy link

@DelliriumX DelliriumX Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this is what I thought would happen. That's what I was telling @DelliriumX over #1527 (comment) - but they seemed pretty sure of themselves 🤷🏻 Figured I was missing something.

So yeah then exporting the types (as-is) does break type inference.

Do not use the Question use what was equivalent to the BuiltInQuestion used inside the prompt. If I can make a type that behaves properly with 1 line of code, inferring from prompt then I see no reason why this cannot be exported from the package.

I think i know what you are getting at. Let me see if i can somehow make it stick

Edit: Okay so here's the conclusion i arrived to after inspecting it a bit more thoroughly.

Types used in the prompt are significantly more complex then the ones I used in the example demonstrated on that comment . There is no way for us to gain the benefits of both inference AND external typing at the same time, but this does not mean that "exporting types (as-is) breaks inference". That said, exporting types wont break inference (using them will break it for that particular function call), though I think what @mshima noted here is a very good point.

With that in mind, people will be able to choose between:

  1. getting inference and inline questions objects
  2. typing questions and typing answers through generics

At least I think this is what the outcome may end up being. Seeing as how with Question/BuiltInQuestion and Answer we can replicate the v9 behaviour. I think that these should be enough to replace the @types/inquirer as it stands right now (well, at least for my use-case it will) because most uses were through DistinctQuestion and that, to my knowledge, had no answer type inference whatsoever - so it should be fine when coupled with Answer replacement for generic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants