Skip to content

Commit d3008e7

Browse files
committed
feat: make deriveds writable
1 parent 6915c12 commit d3008e7

File tree

21 files changed

+65
-175
lines changed

21 files changed

+65
-175
lines changed

.changeset/clever-terms-tell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': minor
3+
---
4+
5+
feat: make deriveds writable

documentation/docs/02-runes/03-$derived.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ Anything read synchronously inside the `$derived` expression (or `$derived.by` f
5252

5353
To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack).
5454

55+
## Overriding derived values
56+
57+
Derived expressions are recalculated when their dependencies change, but you can temporarily override their values by reassigning them. This can be useful for things like _optimistic UI_, where a value is derived from the 'source of truth' (such as data from your server) but you'd like to show immediate feedback to the user.
58+
5559
## Update propagation
5660

5761
Svelte uses something called _push-pull reactivity_ — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull').

packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ export function validate_assignment(node, argument, state) {
2121
const binding = state.scope.get(argument.name);
2222

2323
if (state.analysis.runes) {
24-
if (binding?.kind === 'derived') {
25-
e.constant_assignment(node, 'derived state');
26-
}
27-
2824
if (binding?.node === state.analysis.props_id) {
2925
e.constant_assignment(node, '$props.id()');
3026
}
@@ -38,25 +34,6 @@ export function validate_assignment(node, argument, state) {
3834
e.snippet_parameter_assignment(node);
3935
}
4036
}
41-
if (
42-
argument.type === 'MemberExpression' &&
43-
argument.object.type === 'ThisExpression' &&
44-
(((argument.property.type === 'PrivateIdentifier' || argument.property.type === 'Identifier') &&
45-
state.derived_state.some(
46-
(derived) =>
47-
derived.name === /** @type {PrivateIdentifier | Identifier} */ (argument.property).name &&
48-
derived.private === (argument.property.type === 'PrivateIdentifier')
49-
)) ||
50-
(argument.property.type === 'Literal' &&
51-
argument.property.value &&
52-
typeof argument.property.value === 'string' &&
53-
state.derived_state.some(
54-
(derived) =>
55-
derived.name === /** @type {Literal} */ (argument.property).value && !derived.private
56-
)))
57-
) {
58-
e.constant_assignment(node, 'derived state');
59-
}
6037
}
6138

6239
/**
@@ -81,7 +58,6 @@ export function validate_no_const_assignment(node, argument, scope, is_binding)
8158
} else if (argument.type === 'Identifier') {
8259
const binding = scope.get(argument.name);
8360
if (
84-
binding?.kind === 'derived' ||
8561
binding?.declaration_kind === 'import' ||
8662
(binding?.declaration_kind === 'const' && binding.kind !== 'each')
8763
) {
@@ -96,12 +72,7 @@ export function validate_no_const_assignment(node, argument, scope, is_binding)
9672
// );
9773

9874
// TODO have a more specific error message for assignments to things like `{:then foo}`
99-
const thing =
100-
binding.declaration_kind === 'import'
101-
? 'import'
102-
: binding.kind === 'derived'
103-
? 'derived state'
104-
: 'constant';
75+
const thing = binding.declaration_kind === 'import' ? 'import' : 'constant';
10576

10677
if (is_binding) {
10778
e.constant_binding(node, thing);

packages/svelte/tests/compiler-errors/samples/runes-no-derived-assignment/_config.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-assignment/main.svelte

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/_config.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-binding/main.svelte

Lines changed: 0 additions & 6 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/_config.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-assignment/main.svelte

Lines changed: 0 additions & 10 deletions
This file was deleted.

packages/svelte/tests/compiler-errors/samples/runes-no-derived-state-field-update/_config.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)