diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index d655fb648a2f..64cdcc93b2d2 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -95,12 +95,24 @@ declare namespace $state { : never : never; + /** + * Returns the latest `value`, even if the rest of the UI is suspending + * while async work (such as data loading) completes. + * + * ```svelte + * + * ``` + */ + export function eager(value: T): T; /** * Declares state that is _not_ made deeply reactive — instead of mutating it, * you must reassign it. * * Example: - * ```ts + * ```svelte * * - * * ``` @@ -124,7 +136,7 @@ declare namespace $state { * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: * * Example: - * ```ts + * ```svelte * + + + + + +

{await push(count)}

+ + {#if count !== eager} +

updating

+ {/if} + + {#snippet pending()}{/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-eager/_config.js b/packages/svelte/tests/runtime-runes/samples/async-state-eager/_config.js new file mode 100644 index 000000000000..d1a8eedcd5a6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-eager/_config.js @@ -0,0 +1,42 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + + compileOptions: { + dev: true + }, + + async test({ assert, target }) { + const [count, shift] = target.querySelectorAll('button'); + + shift.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

0

`); + + count.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

0

`); + + count.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

0

`); + + count.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

0

`); + + shift.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

1

`); + + shift.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

2

`); + + shift.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `

3

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-state-eager/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-state-eager/main.svelte new file mode 100644 index 000000000000..c9168b3984c4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-state-eager/main.svelte @@ -0,0 +1,20 @@ + + + + + + +

{await push(count)}

+ + {#snippet pending()}{/snippet} +
diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index a9938fe924c6..c05a79f039d9 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -3193,12 +3193,24 @@ declare namespace $state { : never : never; + /** + * Returns the latest `value`, even if the rest of the UI is suspending + * while async work (such as data loading) completes. + * + * ```svelte + * + * ``` + */ + export function eager(value: T): T; /** * Declares state that is _not_ made deeply reactive — instead of mutating it, * you must reassign it. * * Example: - * ```ts + * ```svelte * * - * * ``` @@ -3222,7 +3234,7 @@ declare namespace $state { * To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: * * Example: - * ```ts + * ```svelte *