diff --git a/packages/svelte/scripts/generate-types.js b/packages/svelte/scripts/generate-types.js index ae44d05590..57f5097a86 100644 --- a/packages/svelte/scripts/generate-types.js +++ b/packages/svelte/scripts/generate-types.js @@ -37,7 +37,7 @@ await createBundle({ [`${pkg.name}/server`]: `${dir}/src/server/index.d.ts`, [`${pkg.name}/store`]: `${dir}/src/store/public.d.ts`, [`${pkg.name}/transition`]: `${dir}/src/transition/public.d.ts`, - [`${pkg.name}/events`]: `${dir}/src/events/index.js`, + [`${pkg.name}/events`]: `${dir}/src/events/public.d.ts`, // TODO remove in Svelte 6 [`${pkg.name}/types/compiler/preprocess`]: `${dir}/src/compiler/preprocess/legacy-public.d.ts`, [`${pkg.name}/types/compiler/interfaces`]: `${dir}/src/compiler/types/legacy-interfaces.d.ts` diff --git a/packages/svelte/src/events/public.d.ts b/packages/svelte/src/events/public.d.ts new file mode 100644 index 0000000000..ff42e523b3 --- /dev/null +++ b/packages/svelte/src/events/public.d.ts @@ -0,0 +1,57 @@ +// Once https://github.com/microsoft/TypeScript/issues/59980 is fixed we can put these overloads into the JSDoc comments of the `on` function + +/** + * Attaches an event handler to the window and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ +export function on( + window: Window, + type: Type, + handler: (this: Window, event: WindowEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined +): () => void; +/** + * Attaches an event handler to the document and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ +export function on( + document: Document, + type: Type, + handler: (this: Document, event: DocumentEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined +): () => void; +/** + * Attaches an event handler to an element and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ +export function on( + element: Element, + type: Type, + handler: (this: Element, event: HTMLElementEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined +): () => void; +/** + * Attaches an event handler to an element and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ +export function on( + element: Element, + type: Type, + handler: (this: Element, event: MediaQueryListEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined +): () => void; +/** + * Attaches an event handler to an element and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ +export function on( + element: EventTarget, + type: string, + handler: EventListener, + options?: AddEventListenerOptions | undefined +): () => void; diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index 0e1624a118..2dd6ae4f58 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -83,30 +83,6 @@ export function create_event(event_name, dom, handler, options) { * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively * (with attributes like `onclick`), which use event delegation for performance reasons * - * @template {HTMLElement} Element - * @template {keyof HTMLElementEventMap} Type - * @overload - * @param {Element} element - * @param {Type} type - * @param {(this: Element, event: HTMLElementEventMap[Type]) => any} handler - * @param {AddEventListenerOptions} [options] - * @returns {() => void} - */ - -/** - * Attaches an event handler to an element and returns a function that removes the handler. Using this - * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively - * (with attributes like `onclick`), which use event delegation for performance reasons - * - * @overload - * @param {EventTarget} element - * @param {string} type - * @param {EventListener} handler - * @param {AddEventListenerOptions} [options] - * @returns {() => void} - */ - -/** * @param {EventTarget} element * @param {string} type * @param {EventListener} handler diff --git a/packages/svelte/tests/types/events.ts b/packages/svelte/tests/types/events.ts index 164d5f8acc..77891952be 100644 --- a/packages/svelte/tests/types/events.ts +++ b/packages/svelte/tests/types/events.ts @@ -4,6 +4,10 @@ import { on } from 'svelte/events'; on(document.body, 'click', (e) => e.button); +on(window, 'click', (e) => e.button); + +on(document, 'click', (e) => e.button); + on( document.body, 'clidck', @@ -12,14 +16,6 @@ on( e.button ); -on( - window, - 'click', - (e) => - // @ts-expect-error ideally we'd know this is a MouseEvent here, too, but for keeping the types sane, we currently don't - e.button -); - on( // @ts-expect-error 'asd', diff --git a/packages/svelte/tsconfig.json b/packages/svelte/tsconfig.json index 0cc600dc74..017b926298 100644 --- a/packages/svelte/tsconfig.json +++ b/packages/svelte/tsconfig.json @@ -19,7 +19,7 @@ "svelte": ["./src/index.d.ts"], "svelte/action": ["./src/action/public.d.ts"], "svelte/compiler": ["./src/compiler/public.d.ts"], - "svelte/events": ["./src/events/index.js"], + "svelte/events": ["./src/events/public.d.ts"], "svelte/internal/client": ["./src/internal/client/index.js"], "svelte/legacy": ["./src/legacy/legacy-client.js"], "svelte/motion": ["./src/motion/public.d.ts"], diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 4981bc5199..9b5bdd727d 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1991,20 +1991,63 @@ declare module 'svelte/transition' { } declare module 'svelte/events' { + // Once https://github.com/microsoft/TypeScript/issues/59980 is fixed we can put these overloads into the JSDoc comments of the `on` function + + /** + * Attaches an event handler to the window and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ + export function on( + window: Window, + type: Type, + handler: (this: Window, event: WindowEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined + ): () => void; + /** + * Attaches an event handler to the document and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ + export function on( + document: Document, + type: Type, + handler: (this: Document, event: DocumentEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined + ): () => void; /** * Attaches an event handler to an element and returns a function that removes the handler. Using this * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively * (with attributes like `onclick`), which use event delegation for performance reasons - * - * */ - export function on(element: Element, type: Type, handler: (this: Element, event: HTMLElementEventMap[Type]) => any, options?: AddEventListenerOptions | undefined): () => void; + */ + export function on( + element: Element, + type: Type, + handler: (this: Element, event: HTMLElementEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined + ): () => void; /** * Attaches an event handler to an element and returns a function that removes the handler. Using this * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively * (with attributes like `onclick`), which use event delegation for performance reasons - * - * */ - export function on(element: EventTarget, type: string, handler: EventListener, options?: AddEventListenerOptions | undefined): () => void; + */ + export function on( + element: Element, + type: Type, + handler: (this: Element, event: MediaQueryListEventMap[Type]) => any, + options?: AddEventListenerOptions | undefined + ): () => void; + /** + * Attaches an event handler to an element and returns a function that removes the handler. Using this + * rather than `addEventListener` will preserve the correct order relative to handlers added declaratively + * (with attributes like `onclick`), which use event delegation for performance reasons + */ + export function on( + element: EventTarget, + type: string, + handler: EventListener, + options?: AddEventListenerOptions | undefined + ): () => void; export {}; }