diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index 31b02a153f..7fdc2b1f7e 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -62,28 +62,44 @@ export function wrap_snippet(component, fn) { }); } +/** + * @template T + * @typedef {{ + * [K in keyof T]: () => T[K]; + * }} LazyParams + */ + /** * Create a snippet imperatively using mount, hyrdate and render functions. + * @template {unknown[]} Params * @param {{ - * mount: (...params: any[]) => Element, - * hydrate?: (element: Element, ...params: any[]) => void, - * render: (...params: any[]) => string + * mount: (...params: LazyParams) => Element, + * hydrate?: (element: Element, ...params: LazyParams) => void, + * render: (...params: Params) => string * }} options + * @returns {import('svelte').Snippet} */ export function createRawSnippet({ mount, hydrate }) { - var snippet_fn = (/** @type {TemplateNode} */ anchor, /** @type {any[]} */ ...params) => { + return add_snippet_symbol((anchor, ...params) => { + /** @type {Element} */ var element; + if (hydrating) { - element = hydrate_node; + element = /** @type {Element} */ (hydrate_node); + + if (hydrate === undefined) { + element = mount(...params); + hydrate_node.replaceWith(element); + } else { + hydrate(element, ...params); + } + hydrate_next(); - if (hydrate !== undefined) hydrate(/** @type {Element} */ (element), ...params); } else { element = mount(...params); anchor.before(element); } - assign_nodes(element, element); - }; - add_snippet_symbol(snippet_fn); - return snippet_fn; + assign_nodes(element, element); + }); } diff --git a/packages/svelte/src/internal/shared/validate.js b/packages/svelte/src/internal/shared/validate.js index 1fb1644d97..6617907f4c 100644 --- a/packages/svelte/src/internal/shared/validate.js +++ b/packages/svelte/src/internal/shared/validate.js @@ -1,3 +1,4 @@ +/** @import { TemplateNode } from '#client' */ import { is_void } from '../../constants.js'; import * as w from './warnings.js'; import * as e from './errors.js'; @@ -5,10 +6,13 @@ import * as e from './errors.js'; const snippet_symbol = Symbol.for('svelte.snippet'); /** - * @param {any} fn + * @param {(anchor: TemplateNode, ...args: any[]) => void} fn + * @returns {import('svelte').Snippet} */ export function add_snippet_symbol(fn) { + // @ts-expect-error fn[snippet_symbol] = true; + // @ts-expect-error return fn; } diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 4219e14d52..f5d3b5f9c3 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -368,11 +368,12 @@ declare module 'svelte' { /** * Create a snippet imperatively using mount, hyrdate and render functions. * */ - export function createRawSnippet({ mount, hydrate }: { - mount: (...params: any[]) => Element; - hydrate?: (element: Element, ...params: any[]) => void; - render: (...params: any[]) => string; - }): (anchor: TemplateNode, ...params: any[]) => void; + export function createRawSnippet({ mount, hydrate }: { + mount: (...params: LazyParams) => Element; + hydrate?: (element: Element, ...params: LazyParams) => void; + render: (...params: Params) => string; + }): import("svelte").Snippet; + type LazyParams = { [K in keyof T]: () => T[K]; }; /** * Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component. * Transitions will play during the initial render unless the `intro` option is set to `false`. @@ -458,7 +459,6 @@ declare module 'svelte' { * https://svelte.dev/docs/svelte#getallcontexts * */ export function getAllContexts = Map>(): T; - type TemplateNode = Text | Element | Comment; export { hydrate_1 as hydrate, mount_1 as mount }; }