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

Improve type inference for the listener callback #19

Merged
merged 1 commit into from
Mar 8, 2021

Conversation

stof
Copy link
Contributor

@stof stof commented Jun 23, 2020

Instead of using a generic Event type for the argument, the map of event types to the corresponding Event object types is used by the inference.

This is a BC break for projects specifying the generic types explicitly, as it changes the generic signature. For project relying on type inference, the inferred type becomes more specific.

@fregante fregante self-requested a review June 23, 2020 13:05
@fregante fregante added the enhancement New feature or request label Jul 11, 2020
@fregante
Copy link
Owner

fregante commented Jul 11, 2020

I'm not sure of how this is different. If you pass FocusEvent to v2, isn't it exactly the same as passing 'focus' here?

@stof
Copy link
Contributor Author

stof commented Aug 11, 2020

the difference is that delegate(element, '.my-class', 'click', function (event) {}) will automatically infer the type of event without having to specify it, based on the click event type.
Type inference is all about not passing the type explicitly.

@fregante
Copy link
Owner

That would be good if it works, but I just tried it locally and it doesn't seem to infer the type:

Inferred ❌

Specified ✅

@stof
Copy link
Contributor Author

stof commented Aug 12, 2020

what happens if you run delegate(document, '.js-comment-field, #commit-description-textarea', 'keydown', event => { ... } ? Maybe typescript enables the type inference only when the generic is not specified at all and keeps the default types for partially specified ones.

@fregante
Copy link
Owner

fregante commented Aug 12, 2020

That's strange:

I'm not sure I like that this forces me to write <HTMLTextAreaElement, 'keydown'> though. . Can you find out why this happens or if there's a way around it?

@stof
Copy link
Contributor Author

stof commented Aug 12, 2020

Well, my best guess is that the type inference for generic types is done only when not specifying it at all, but not when specifying part of it and not next ones.

Btw, with the existing code, delegate<HTMLTextarea>(...) would then still report it asdelegate.Event(Event, HTMLTextAreaElement) and not as KeyboardEvent. So I'm not sure whether the partial case is worse then before (the IDE shows a big union type, but all types in it are extending Event which is also part of the union)

@stof
Copy link
Contributor Author

stof commented Aug 12, 2020

For the record, my own usage is that I write JavaScript code, not TypeScript code. But I still rely on typescript type definitions for type checking (tsc --checkJS) and IDE intellisense (both PHPStorm and VS Code are using them).
As JS code cannot specify generic types for function calls, my own usage always goes to the delegate(document, '.js-comment-field, #commit-description-textarea', 'keydown', event => { ... }) syntax which benefits from the improvement.
I opened an issue in the TypeScript issue tracker to see whether a future version of TS could enable type inference for partially-specified generics.

@fregante
Copy link
Owner

fregante commented Aug 18, 2020

I want to merge this but is it possible to achieve the same effect without changing the generic? For 2 reasons:

@stof
Copy link
Contributor Author

stof commented Aug 18, 2020

Well, I don't think it is possible without changing it. The change of generic is precisely what allows the event type argument to specify the event class in the generic.

index.ts Outdated Show resolved Hide resolved
@fregante
Copy link
Owner

Can you change it so the generic takes 2 strings? At least it's both consistent and shorter

Before

<HTMLTextAreaElement, KeyboardEvent>

This PR

<HTMLTextAreaElement, 'keydown'>

Suggested

<'textarea', 'keydown'>

@fregante fregante marked this pull request as draft November 9, 2020 19:15
Instead of using a generic Event type for the argument, the map of event types to the corresponding Event object types is used by the inference.

This is a BC break for projects specifying the generic types explicitly, as it changes the generic signature. For project relying on type inference, the inferred type becomes more specific.
@stof
Copy link
Contributor Author

stof commented Feb 23, 2021

@fregante your suggestion using tag names rather than the element type will be harder to implement: HTML and SVG elements are in separate maps in the dom lib of typescript. And they even have some common tag names associated to different element types, which would then forbid using one of them. And things would also become harder to support custom elements.

Currently, the library supports any kind of Element without any additional need to register the custom element types in a special way. And this will not improve type inference AFAICT (maybe even regress it)

@fregante
Copy link
Owner

fregante commented Feb 23, 2021

It can be done, querySelector maps tag selectors to their constructors and in my select-dom I use a dependency to do the same (but supporting whole selectors), but yeah it might be a little tough. However it’s basically the same concept as this change, nobody guarantees that an input event is actually InputEvent and not a CustomEvent

I’ll test this in my other project and I’ll merge it as is for now. Then I’ll think if it’s worth the other part of the change.

@fregante fregante marked this pull request as ready for review February 23, 2021 13:00
Copy link
Owner

@fregante fregante left a comment

Choose a reason for hiding this comment

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

💙

@fregante
Copy link
Owner

Now that I think of it, I could use the same package exactly the same way since this module also takes a selector. This way no one probably even needs to specify anything via generics.

@fregante fregante merged commit 46a07f7 into fregante:master Mar 8, 2021
@fregante
Copy link
Owner

fregante commented Mar 8, 2021

Thank you for this and sorry for the long wait! I'll open a new issue for the other part of the feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request wait for major
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants