Repository navigation
Type inference failing for window.onbeforeunload #39057
Description
Activity
Context: Error here when upgrading to TS 3.9: https://github.com/felixrieseberg/windows95/blob/1dd3b761873d8f31eef9aa02f06135495d972ed9/src/renderer/emulator.tsx#L102
I understand Wesley Wigham (@weswigham) may have been working on this kind of signature intersection.
I just have a question: Why is
onbeforeunloaddefined as an intersection of function types? What does it even mean to intersect function types, practically speaking? The concept seems kind of mind-bending to me.edit: Nevermind, ignore me, I'm stupid. I forgot that intersection is how TS represents overloaded functions.
Bruce Pascoe (@fatcerberus) The immediate answer to your question is that it's declared both here and here . I don't know why that's the case though - something about global
this.- addedNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
on Jun 16, 2020 This can be fixed by making the
lib.dom.d.tstypes more precise, namelydeclare var onafterprint: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare var onbeforeprint: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare var onbeforeunload: ((this: Window & typeof globalThis, ev: BeforeUnloadEvent) => any) | null; declare var onhashchange: ((this: Window & typeof globalThis, ev: HashChangeEvent) => any) | null; declare var onlanguagechange: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare var onmessage: ((this: Window & typeof globalThis, ev: MessageEvent) => any) | null; declare var onmessageerror: ((this: Window & typeof globalThis, ev: MessageEvent) => any) | null; declare var onoffline: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare var ononline: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare var onpagehide: ((this: Window & typeof globalThis, ev: PageTransitionEvent) => any) | null; declare var onpageshow: ((this: Window & typeof globalThis, ev: PageTransitionEvent) => any) | null; declare var onpopstate: ((this: Window & typeof globalThis, ev: PopStateEvent) => any) | null; declare var onrejectionhandled: ((this: Window & typeof globalThis, ev: PromiseRejectionEvent) => any) | null; declare var onstorage: ((this: Window & typeof globalThis, ev: StorageEvent) => any) | null; declare var onunhandledrejection: ((this: Window & typeof globalThis, ev: PromiseRejectionEvent) => any) | null; declare var onunload: ((this: Window & typeof globalThis, ev: Event) => any) | null; declare function addEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window & typeof globalThis, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; declare function removeEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window & typeof globalThis, ev: WindowEventMap[K]) => any, options?: boolean | EventListenerOptions): void; declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
and
interface WindowEventHandlers { onafterprint: ((this: this, ev: Event) => any) | null; onbeforeprint: ((this: this, ev: Event) => any) | null; onbeforeunload: ((this: this, ev: BeforeUnloadEvent) => any) | null; onhashchange: ((this: this, ev: HashChangeEvent) => any) | null; onlanguagechange: ((this: this, ev: Event) => any) | null; onmessage: ((this: this, ev: MessageEvent) => any) | null; onmessageerror: ((this: this, ev: MessageEvent) => any) | null; onoffline: ((this: this, ev: Event) => any) | null; ononline: ((this: this, ev: Event) => any) | null; onpagehide: ((this: this, ev: PageTransitionEvent) => any) | null; onpageshow: ((this: this, ev: PageTransitionEvent) => any) | null; onpopstate: ((this: this, ev: PopStateEvent) => any) | null; onrejectionhandled: ((this: this, ev: PromiseRejectionEvent) => any) | null; onstorage: ((this: this, ev: StorageEvent) => any) | null; onunhandledrejection: ((this: this, ev: PromiseRejectionEvent) => any) | null; onunload: ((this: this, ev: Event) => any) | null; addEventListener<K extends keyof WindowEventHandlersEventMap>(type: K, listener: (this: this, ev: WindowEventHandlersEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; removeEventListener<K extends keyof WindowEventHandlersEventMap>(type: K, listener: (this: this, ev: WindowEventHandlersEventMap[K]) => any, options?: boolean | EventListenerOptions): void; removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; }
By using
this: thisinWindowEventHandlers(which, in turn, becomesWindow & typeof globalThisfor the interface's use in thewindowobject) andWindow & typeof globalThisin the actual global variable definitions (rather than justWindow, which is technically incomplete), we ensure thethistypes of both signatures are identical, which then allows us to apply contextual types as expected.Nathan Shively-Sanders (@sandersn) how does making the above changes sound to you? This regression would seem to be a consequence of using
declare var window: Window & typeof globalThis;forwindow, which is a year old (circa #32335).Context: Error here when upgrading to TS 3.9:
I'm not so sure the error is from upgrading to 3.9 - I can actually see the same behavior in 3.7.2, the current version of TS on felixrieseberg/windows95. (Not that it may not still stand to be improved) Indeed, I don't think
electron-forge make(what runs on CI) actually reports TS errors at build time. So the project just... has TS errors.sandersn commented
on Jun 24, 2020 MemberMore actionsThe first change sounds good. The second change adds
thisto an interface, so we'd need to check performance, but I don't think there will be THAT many instantiations ofWindowEventHandlers.Let's do this in 4.1 since it's been around without a lot of people noticing.
- addedRescheduledThis issue was previously scheduled to an earlier milestoneThis issue was previously scheduled to an earlier milestone
on Dec 11, 2020 3 remaining items
RyanCavanaugh commented
on Feb 15, 2023 MemberMore actionsThis works as expected now
TypeScript Version: playground nightly (2020-06-12)
Search Terms: window event inference any
Code
Expected behavior:
eventhas typeBeforeUnloadEventActual behavior:
eventhas typeany(resulting in an erro)Playground Link: https://www.typescriptlang.org/play/?ts=4.0.0-dev.20200611#code/O4SwdgJg9sB0VgEYFMBmUBOyCuYA2UAhhAAQC8JyAbsmAC7kB8lN9A3EA
Related Issues: