Skip to content

Commit 3624a4c

Browse files
authored
feat: allow modifiying derived props (#10080)
It's an unnecessary restruction because it can be worked around (hide it behind a getter/setter), already works for bind:x and prevents valid use cases
1 parent b623890 commit 3624a4c

File tree

6 files changed

+38
-11
lines changed

6 files changed

+38
-11
lines changed

.changeset/hungry-trees-travel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
feat: allow modifiying derived props

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,13 @@ function validate_assignment(node, argument, state) {
854854

855855
let left = /** @type {import('estree').Expression | import('estree').Super} */ (argument);
856856

857+
if (left.type === 'Identifier') {
858+
const binding = state.scope.get(left.name);
859+
if (binding?.kind === 'derived') {
860+
error(node, 'invalid-derived-assignment');
861+
}
862+
}
863+
857864
/** @type {import('estree').Expression | import('estree').PrivateIdentifier | null} */
858865
let property = null;
859866

@@ -862,13 +869,6 @@ function validate_assignment(node, argument, state) {
862869
left = left.object;
863870
}
864871

865-
if (left.type === 'Identifier') {
866-
const binding = state.scope.get(left.name);
867-
if (binding?.kind === 'derived') {
868-
error(node, 'invalid-derived-assignment');
869-
}
870-
}
871-
872872
if (left.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
873873
if (state.private_derived_state.includes(property.name)) {
874874
error(node, 'invalid-derived-assignment');
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
22
const a = $state(0);
3-
const b = $derived({ a });
4-
b.a += 1;
3+
let b = $derived(a);
4+
b = 1;
55
</script>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
22
const a = $state(0);
3-
const b = $derived({ a });
4-
b.a++;
3+
let b = $derived(a);
4+
b++;
55
</script>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: `<button>0 / 0</button><button>0 / 0</button>`,
5+
6+
async test({ assert, target }) {
7+
const [btn1, btn2] = target.querySelectorAll('button');
8+
9+
await btn1?.click();
10+
assert.htmlEqual(target.innerHTML, `<button>1 / 2</button><button>1 / 2</button>`);
11+
12+
await btn2?.click();
13+
assert.htmlEqual(target.innerHTML, `<button>2 / 4</button><button>2 / 4</button>`);
14+
}
15+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let count = $state(0);
3+
let double = $derived({ get value() { return count * 2}, set value(c) { count = c / 2 } });
4+
</script>
5+
6+
<button on:click={() => count++}>{count} / {double.value}</button>
7+
<button on:click={() => double.value += 2}>{count} / {double.value}</button>

0 commit comments

Comments
 (0)