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

Dynamically determine the type of ctx.match #81

Closed
wants to merge 9 commits into from

Conversation

KnightNiwrem
Copy link
Contributor

@KnightNiwrem KnightNiwrem commented Nov 7, 2021

bot.hears('a string', ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // ok
  console.log(matches?.groups); // error
}).use(ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // ok
  console.log(matches?.groups); // error
});

bot.hears(['a string'], ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // ok
  console.log(matches?.groups); // error
});

bot.hears(/a regexp/, ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // error
  console.log(matches?.groups); // ok
});

bot.hears([/a regexp/], ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // error
  console.log(matches?.groups); // ok
});

bot.hears(['a mixed array', /of string and regexp/], ctx => {
  const matches = ctx.match;
  console.log(matches?.toLowerCase()); // error
  console.log(matches?.groups); // error

  if (typeof matches === "string") {
    console.log(matches?.toLowerCase()); // ok
    console.log(matches?.groups); // error
  } else {
    console.log(matches?.toLowerCase()); // error
    console.log(matches?.groups); // ok
  }
});

Copy link
Member

@KnorpelSenf KnorpelSenf left a comment

Choose a reason for hiding this comment

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

You're calling it the verbose edition—is there a second PR that is less verbose, or what does this name imply?

Generally it looks like a good way to tackle this problem. However, I don't like at all how verbose things get because of this. I'm against merging unless we manage to cut it down.

src/composer.ts Outdated Show resolved Hide resolved
Comment on lines +557 to +600
trigger: MaybeNonEmptyArray<string>,
...middleware: Array<
Middleware<FilteredMatchContext<C, string, "callback_query:data">>
>
): Composer<FilteredMatchContext<C, string, "callback_query:data">>;
callbackQuery(
trigger: MaybeNonEmptyArray<RegExp>,
...middleware: Array<
Middleware<
FilteredMatchContext<C, RegExpMatchArray, "callback_query:data">
>
>
): Composer<
FilteredMatchContext<C, RegExpMatchArray, "callback_query:data">
>;
callbackQuery(
trigger: MustMixedNonEmptyArrayType<string, RegExp>,
...middleware: Array<
Middleware<
FilteredMatchContext<
C,
string | RegExpMatchArray,
"callback_query:data"
>
>
>
): Composer<
FilteredMatchContext<
C,
string | RegExpMatchArray,
"callback_query:data"
>
>;
callbackQuery(
trigger: MaybeNonEmptyArray<string | RegExp>,
...middleware: Array<
Middleware<
FilteredMatchContext<
C,
string | RegExpMatchArray,
"callback_query:data"
>
>
>
Copy link
Member

Choose a reason for hiding this comment

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

Is there a way to make this less verbose? I'm as uncomfortable as you probably are with half of the code in this file being type annotations of function overloads.

src/composer.ts Outdated Show resolved Hide resolved
src/composer.ts Outdated Show resolved Hide resolved
@@ -74,7 +74,7 @@ export class Context implements RenamedUpdate {
* Used by some middleware to store information about how a certain string
* or regular expression was matched.
*/
public match?: string | RegExpMatchArray | null;
public match?: string | RegExpMatchArray;
Copy link
Member

Choose a reason for hiding this comment

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

Nice catch!

src/filter.ts Outdated Show resolved Hide resolved
@KnightNiwrem
Copy link
Contributor Author

You're calling it the verbose edition—is there a second PR that is less verbose, or what does this name imply?

Generally it looks like a good way to tackle this problem. However, I don't like at all how verbose things get because of this. I'm against merging unless we manage to cut it down.

Agreed. There isn't a second PR that is less verbose.. or at least there wasn't. But I've managed to find a way to avoid code duplication for now, at the expense of longer type parameters

@KnightNiwrem KnightNiwrem changed the title Dynamically determine the type of ctx.match (verbose edition) Dynamically determine the type of ctx.match (less verbose edition) Nov 7, 2021
@KnightNiwrem KnightNiwrem changed the title Dynamically determine the type of ctx.match (less verbose edition) Dynamically determine the type of ctx.match Nov 7, 2021
Copy link
Member

@KnorpelSenf KnorpelSenf left a comment

Choose a reason for hiding this comment

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

Less lines, but now we're having wrong type annotations.

src/composer.ts Outdated Show resolved Hide resolved
src/composer.ts Outdated Show resolved Hide resolved
src/composer.ts Outdated Show resolved Hide resolved
@KnorpelSenf
Copy link
Member

KnorpelSenf commented Nov 13, 2021

I need some more time to investigate this. Kinda want to see this merged, but still trying to make it more readable. Novice TS users need to be able to read the type annotations and get at least an idea of what this does.

@KnorpelSenf KnorpelSenf added enhancement New feature or request needs investigation Description is clear but cause is unknown labels Nov 22, 2021
@KnorpelSenf
Copy link
Member

I appreciate your effort and I still want to see this problem solved, but the type annotations that are necessary to make this happen are getting out of hand. The annotations are not straightforward, and if we as developers of grammY think that, then it's already way to complicated for users, especially for the beginners among them. I do not support this change.

In addition, #100 is going to complicate the implementation further. Do we then need four different kinds of context types, four different kinds of middleware types, and all of that for all affected methods?

I am open to split hears and its sibling into two methods, such as hears/hearsRegex, or hearsExact/hears, where the former matches strings, and the latter matches regular expressions, respectively.

Alternatively, we may look into disallowing mixing strings and regex in array on the type level. If anyone needs this, they could type-case explicitly to make it work, as the runtime code can continue supporting it.

Either way, the change would need to be backed by the community. For example, if people mind having multiple almost identical methods more than minding the small inaccuracy in types, then we obviously will not touch the current code. Moreover, both suggestions are breaking changes, so they would have to wait until the next major release.

Either way, I am going to close this PR for now. We may come back to it if anyone can think of a novel way to solve this, or if the tooling changes (who knows what TS does next).

Thank you again for this attempt!

@KnorpelSenf KnorpelSenf deleted the dynamic-ctx-match-types branch May 3, 2022 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request needs investigation Description is clear but cause is unknown
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants