-
Notifications
You must be signed in to change notification settings - Fork 421
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
Generic DOM Events #1624
base: main
Are you sure you want to change the base?
Generic DOM Events #1624
Conversation
Thanks for the PR! This section of the codebase is owned by @saschanaz - if they write a comment saying "LGTM" then it will be merged. |
@microsoft-github-policy-service agree |
But the main point is: is the performance issue solved?
|
@HolgerJeromin That is a good question. Not sure how to measure that. But the previous implementation was a very long time ago (I believe it was implemented on F#) and TypeScript has come a long way in terms of type performance since then, so I'm optimistic. Maybe an admin can hint me how to check the performance is on acceptable levels? |
The resulting type is still same, the fact the generator was in F# doesn't mean much here. Whether the TypeScript itself has some performance improvement, that would be a better question. You should be able to pass a diagnostics flag to check it. https://github.com/microsoft/TypeScript/wiki/Performance#extendeddiagnostics |
@saschanaz should the extendeddiagnostics be run on my branch codebase or in a typescript project that uses it? Here is the output of running it on my current branch:
vs the one runned on main:
|
Both, because otherwise a comparison can't be made 😁 |
Which command are you using btw? |
|
And any more arguments? Last time I think I passed |
@saschanaz running both main and mine branch with that flag gives a few errors (sorry, i'm not very fluent in special settings of tsc) but yields these results: main
generic-dom:
|
Did you run |
@saschanaz I did run
Was this OK or did I do something wrong? |
The result is strange because it seems nothing is different, and that shouldn't be the case? |
Do you think maybe someone could double check in case I'm goofing somewhere? |
@saschanaz my tests running on a project importing this branch as dependency yields similar results. Not sure how to continue from here |
These changes are a great improvement, but adding the same type to |
@DaSchTour After learning a bit more about |
Really hoping to see this PR prioritized and moved along soon - a month without feedback on this issue is too long! this is one of the oldest and most frustrating issues in TypeScript - it literally impacts every browser based project, and it's probably a big reason why some people still feel TS "gets in their way". Dealing with events is so common and just should not be the stumbling block it is today, frankly, performance be damned - if having the correct types for something as essential as browser events drastically impacts performance, then the team should prioritize solving that next. "make it work, make it right, make it fast" - please let's move past step one of three. Projects that would be substantially impacted by any performance issue with generic events already are, as they're just building it themselves. (React, etc.) At the very least, please consider making this available as a separate, opt-in standard type library, so teams can decide for themselves what's more important or where they feel their time is best spent. After 10+ years of waiting, please do something to move forward this time. 🙏 |
Finally got some time to take a look. Without this patch:
With this patch: (ignore the times, those are not very stable)
Difference exists, but not too much compared to how much the community wants this feature. This kind of performance difference can absolutely happen when more types are added e.g. in #1514. @sandersn, does this look okay for you? But this patch can't be merged as-is:
|
BTW, this patch does not cover |
Hey @saschanaz! I updated the PR with the following changes:
Regarding the Let me know your thoughts. |
Every *Types.json is manual, autogeneration happens from https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/main/src/build/emitter.ts. Specifically I think this part can be modified for events: TypeScript-DOM-lib-generator/src/build/emitter.ts Lines 1187 to 1219 in 9524e54
My point is: const input = document.querySelector("input");
input.onchange = ev => {
ev.currentTarget; // Still EventTarget, we want HTMLInputElement
} My suggested work items:
|
03b3857
to
898bad6
Compare
Hi @saschanaz I made some time to check the code and moved the Does this implementation go along the lines you had in mind? Do you think the onevent methods should be handled in a similar way? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This certainly looks better, have you compared performance with the latest changes?
@@ -62,6 +62,8 @@ export const baseTypeConversionMap = new Map<string, string>([ | |||
["EventHandler", "EventHandler"], | |||
]); | |||
|
|||
export const genericEventSupertypes = new Set(["UIEvent", "MouseEvent"]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expected this to cover every event, why should it be limited?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will allow to support dispatched events in future (just idea).
const event /* : MouseEvent<never> */ = new MouseEvent("click")
button.addEventListener("click", (event /* : MouseEvent<HTMLButtonElement> */) => {})
Also important - CustomEvent
, MessageEvent
and ProgressEvent
already use T
type parameter. Could we use other type parameter name for currentTarget
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expected this to cover every event, why should it be limited?
I just thought it might be useful to be able to limit the implementation to DOM events in case performance became an issue, but I guess we could apply this to every Event
subtype, if you think it is better.
CustomEvent, MessageEvent and ProgressEvent already use T type parameter. Could we use other type parameter name for currentTarget?
I was being conservative about the change, so the current implementation only takes interfaces that have no type parameter defined (I made it so there would not be unexpected conflicts) so, for those types we could override on the json files. But yes, we could instead always use another name if that seems better. Does something like Target
sound good? I'm not sure how opinionated is the project regarding names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated request - use T
for currentTarget
type parameter in all events.
For ProgressEvent
it will be common type parameter for both targets (now it's used for target
only).
For MessgegeEvent.data
and CustomEvent.details
we can use D
as type parameter name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In BaseSyntheticEvent
from @types/react
C
- currentTarget
T
- target
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just thought it might be useful to be able to limit the implementation to DOM events in case performance became an issue, but I guess we could apply this to every
Event
subtype, if you think it is better.
We should first check the difference and then decide based on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@turansky @saschanaz Ok, I'll see to handle all events instead of whitelisting and will rename the mentioned type parameters to D
.
In the meantime, I updated the PR with a possible approach to type the onevent
handlers for the currently handled interfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nscarcella FYI - I implemented similar changes in Kotlin Wrappers.
I used followings script:
- Remove
T
type parameter fromProgressEvent
- To replace it later with common
C
- To replace it later with common
D
type parameter forCustomEvent
andMessageEvent
T
reserved as future type parameter fortarget
(will work fine in handlers likeFileReader.onload
)
C
- type parameter forcurrentTarget
for all events
In Kotlin we also received strict dispatched events (with nonnull currentTarget
) as bonus.
In TypeScript it can be solved in separate PR.
@@ -1186,6 +1207,8 @@ export function emitWebIdl( | |||
|
|||
function emitInterfaceDeclaration(i: Browser.Interface) { | |||
function processIName(iName: string) { | |||
if (iName === "GlobalEventHandlers" && i.name !== iName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is the right approach or this should be declared on the json files.
Hopefully fixes microsoft/TypeScript#299
Added generics to Events so that
target
andcurrentTarget
's types can be parameterized and event listeners can take a callback that expects an event targeting the receiver's type.All new generics have default values, so the change should be backward compatible and all tests seem to be passing.
This is my first PR to the project and I hope I'm following the community norms, but please let me know if the implementation is up to standards or something is amiss.