fix: [#2064] Defensively initialize EventTarget listener maps#2075
Open
TrevorBurnham wants to merge 1 commit intocapricorn86:masterfrom
Open
fix: [#2064] Defensively initialize EventTarget listener maps#2075TrevorBurnham wants to merge 1 commit intocapricorn86:masterfrom
TrevorBurnham wants to merge 1 commit intocapricorn86:masterfrom
Conversation
EventTarget.addEventListener(), removeEventListener(), dispatchEvent(), and destroy() now defensively initialize PropertySymbol.listeners and PropertySymbol.listenerOptions if they are undefined. Class field initializers only run when the constructor executes. If a third-party library creates an object that inherits from EventTarget without calling super() (or attaches listeners before the initializers have run), the internal maps are undefined and every method that accesses them throws a TypeError. The fix adds an ensureListenerMaps() helper that lazily creates the maps on first access, keeping the normal (already-initialized) path as a single falsy check with no allocation. Closes capricorn86#2064
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2064
Problem
EventTarget.addEventListener()throws aTypeErrorwhenPropertySymbol.listenersorPropertySymbol.listenerOptionsisundefined:This happens when third-party libraries (e.g. PixiJS) attach event listeners very early in their initialization process, before the class field initializers on
EventTargethave run. Since thelistenersandlistenerOptionsmaps are initialized as class fields, they only exist after the constructor completes. Objects that inherit fromEventTargetwithout callingsuper(), or that interact with the prototype before construction finishes, hitundefined.Fix
Added an
ensureListenerMaps()helper function that lazily initializes both maps if they areundefined. It is called at the entry point of:addEventListener()removeEventListener()#callDispatchEventListeners()(internal, used bydispatchEvent())The
destroy()method also guards againstundefinedwith an early return.On the normal path (maps already initialized), this is a single falsy check with zero allocation.
Test
Added a test that simulates the uninitialized state by constructing an
EventTargetand then forcibly clearing both internal maps toundefined. Verifies thataddEventListener,dispatchEvent, andremoveEventListenerall work without throwing.