From c85120fb9fb4ff500bef189368f31b680421c4ba Mon Sep 17 00:00:00 2001 From: "svelte-triage-bot[bot]" <316883489+svelte-triage-bot[bot]@users.noreply.github.com> Date: Wed, 7 Oct 2026 11:44:42 +0200 Subject: [PATCH] fix: track missing proxy keys in unowned deriveds (#18944) Co-authored-by: svelte-triage-bot --- .../reactive-missing-property-checks.md | 5 +++ packages/svelte/src/internal/client/proxy.js | 3 +- packages/svelte/tests/signals/test.ts | 40 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 .changeset/reactive-missing-property-checks.md diff --git a/.changeset/reactive-missing-property-checks.md b/.changeset/reactive-missing-property-checks.md new file mode 100644 index 0000000000..c4b5f7105c --- /dev/null +++ b/.changeset/reactive-missing-property-checks.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: track missing state property checks in unowned deriveds diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index d7e8c98896..db58459fd9 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -2,7 +2,6 @@ import { DEV } from 'esm-env'; import { get, - active_effect, update_version, active_reaction, set_update_version, @@ -241,7 +240,7 @@ export function proxy(value) { if ( s !== undefined || - (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) + (active_reaction !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { s = with_parent(() => { diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 2d2d653c03..b83e75a767 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -153,6 +153,46 @@ describe('signals', () => { }; }); + test('unowned deriveds track missing property checks on proxies', () => { + const value = proxy>({}); + + return () => { + const has_x = derived(() => 'x' in value); + const owns_y = derived(() => Object.hasOwn(value, 'y')); + + assert.isFalse($.get(has_x)); + assert.isFalse($.get(owns_y)); + + value.x = true; + value.y = true; + + assert.isTrue($.get(has_x)); + assert.isTrue($.get(owns_y)); + + delete value.x; + delete value.y; + + assert.isFalse($.get(has_x)); + assert.isFalse($.get(owns_y)); + }; + }); + + test('unowned deriveds track missing array indexes', () => { + const value = proxy([]); + + return () => { + const has_first = derived(() => 0 in value); + + assert.isFalse($.get(has_first)); + + value.push(true); + assert.isTrue($.get(has_first)); + + value.length = 0; + assert.isFalse($.get(has_first)); + }; + }); + test('derived from state', () => { const log: number[] = [];