diff --git a/.changeset/twenty-bears-fly.md b/.changeset/twenty-bears-fly.md new file mode 100644 index 0000000000..e32299c2d3 --- /dev/null +++ b/.changeset/twenty-bears-fly.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: enhance snapshot type handling for array structures in $state.snapshot diff --git a/packages/svelte/src/ambient.d.ts b/packages/svelte/src/ambient.d.ts index bbbc86c997..8cd9f38916 100644 --- a/packages/svelte/src/ambient.d.ts +++ b/packages/svelte/src/ambient.d.ts @@ -86,7 +86,13 @@ declare namespace $state { : T extends { toJSON(): infer R } ? R : T extends readonly unknown[] - ? { [K in keyof T]: Snapshot } + ? number extends T['length'] + ? T extends Array + ? Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : never + : { [K in keyof T]: Snapshot } : T extends Array ? Array> : T extends object diff --git a/packages/svelte/tests/types/state.ts b/packages/svelte/tests/types/state.ts new file mode 100644 index 0000000000..989a497b59 --- /dev/null +++ b/packages/svelte/tests/types/state.ts @@ -0,0 +1,15 @@ +import type { ClassValue } from 'clsx'; + +// Regression test for #17117: this should not trigger deep/infinite type instantiation +const cls = $state.raw([]); +const cls_snap: ReturnType> = + $state.snapshot(cls); + +type SnapshotTuple = ReturnType>; + +const tuple_ok: SnapshotTuple = [1, 'a']; +tuple_ok[0] === 1; +tuple_ok[1] === 'a'; + +// @ts-expect-error tuple element type should be preserved +const tuple_wrong: SnapshotTuple = [1, 2]; diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 3f71d44177..83b2bfb2a6 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -3284,7 +3284,13 @@ declare namespace $state { : T extends { toJSON(): infer R } ? R : T extends readonly unknown[] - ? { [K in keyof T]: Snapshot } + ? number extends T['length'] + ? T extends Array + ? Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : never + : { [K in keyof T]: Snapshot } : T extends Array ? Array> : T extends object