diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index 4e98eb82eb..e9dbf502bf 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -234,7 +234,7 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void)): void; +declare function $effect(fn: () => void | (() => void) | AbortController): void; declare namespace $effect { /** @@ -253,7 +253,7 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void)): void; + export function pre(fn: () => void | (() => void) | AbortController): void; /** * The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template. diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index bf890627f7..ddacd09246 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -381,7 +381,11 @@ export function execute_effect_teardown(effect) { set_is_destroying_effect(true); set_active_reaction(null); try { - teardown.call(null); + if (typeof teardown === 'function') { + teardown.call(null); + } else { + teardown.abort('effect destroyed'); + } } finally { set_is_destroying_effect(previously_destroying_effect); set_active_reaction(previous_reaction); diff --git a/packages/svelte/src/internal/client/reactivity/types.d.ts b/packages/svelte/src/internal/client/reactivity/types.d.ts index 13e14414b5..77cf474aea 100644 --- a/packages/svelte/src/internal/client/reactivity/types.d.ts +++ b/packages/svelte/src/internal/client/reactivity/types.d.ts @@ -52,7 +52,7 @@ export interface Effect extends Reaction { /** The effect function */ fn: null | (() => void | (() => void)); /** The teardown function returned from the effect function */ - teardown: null | (() => void); + teardown: null | (() => void) | AbortController; /** Transition managers created with `$.transition` */ transitions: null | TransitionManager[]; /** Next sibling child effect created inside the parent signal */ diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 4aa3d17a15..101d0e9742 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -524,8 +524,12 @@ export function update_effect(effect) { destroy_effect_deriveds(effect); execute_effect_teardown(effect); - var teardown = update_reaction(effect); - effect.teardown = typeof teardown === 'function' ? teardown : null; + var teardown = update_reaction(effect) ?? null; + // Avoid doing an instanceof check on the hot-path + effect.teardown = + teardown === null || typeof teardown === 'function' || teardown instanceof AbortController + ? teardown + : null; effect.version = current_version; if (DEV) { diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 671f68bff7..9ef55d766f 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -2892,7 +2892,7 @@ declare namespace $derived { * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute */ -declare function $effect(fn: () => void | (() => void)): void; +declare function $effect(fn: () => void | (() => void) | AbortController): void; declare namespace $effect { /** @@ -2911,7 +2911,7 @@ declare namespace $effect { * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute */ - export function pre(fn: () => void | (() => void)): void; + export function pre(fn: () => void | (() => void) | AbortController): void; /** * The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template.