svelte
svelte copied to clipboard
Svelte 5: unable to name a variable with the "same name" as a rune
Describe the bug
When naming a variable with the same name as a rune, without the $, like state or derived or others, the compiler considers them as the same, thus leading to errors like Cannot access 'state' before initialization or errors relating to rune re-affectation.
Even if it's not a bug, runes re-affectation should be prohibited.
Reproduction
https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACj2N0QqDMAxFfyUEH9wQHHsaVQf7jrkH10ZWqG1pU2GI_z46N99yT3JPFhy1oYjivqAdJkKBN--xQn77HOJMhgkrjC4FmUm7IeE8a2cjhGQpQn3tbW_bKIP2nGc2xCBdsgwdFJEHpvJ0aPJGOhsZvgg6uGS2U0VBz6Sggx5fZIzrsfnblEtPkyvF76rc_Ec4Z3Fb79-xwskpPWpSKDgkWh_rB8K78zLqAAAA
Logs
No response
System Info
REPL, Svelte 5 next 175
Severity
annoyance
It's not really about runes but stores — if you declare a variable state, then $state is considered a store value, and thus, the error is that you are trying to read a store before its declaration. So, in general, the error is correct, though it can be misleading.
@7nik yes indeed, makes sense! I'm quite new to using runes, so I kind of forgot about stores as I was focused on playing around with runes, but yeah, that makes sense.
In my opinion, there are two possible solutions here:
- Allow naming variables with the same name as runes, but prohibit creating stores with those names (seems quite hard with JS versatility)
- Completely disallow variable creation with those names
Both are not easily feasible:
- when you have code like
let state = getSomeResultFromSomewhereElse(), it is not feasible for svelte to detect what type(s) that could be. That would make this a runtime warning, which is not ideal at all - Forbidding variables with the same names as runes would make adding new runes a breaking change (as more variable names are forbidden, which could break code).
Afaik because of those reasons, runes with the same names as variables are automatically disabled
The first solution is impossible. Static analysis cannot cover all possible cases. IIRC, variables shadowing runes is intention behaviour - this allows the introduction of new runes without breaking existing code. But a warning should probably be emitted in this case. BTW, due to this, your REPL is considered to be in legacy mode.
BTW, due to this, your REPL is considered to be in legacy mode.
What does that mean?
- Forbidding variables with the same names as runes would make adding new runes a breaking change (as more variable names are forbidden, which could break code).
That's true... What's the best way around it then? A simply better warning message?
BTW, due to this, your REPL is considered to be in legacy mode.
What does that mean?
Svelte 4 / non-rune mode.
The mode can be switched with <svelte:options runes /> or runes: true in the compiler options.
Svelte 4 / non-rune mode.
Weird, it was in Svelte 5 when I posted it. Fixed.
There is already a warning for this problem, as you can see in the REPL.
The current warning implies overriding runes is allowed, not that such a thing is not possible and the variable should be renamed
The current warning implies overriding runes is allowed, not that such a thing is not possible and the variable should be renamed
I didn't interpret the warning to imply that you could override runes, more that the naming of your variable conflicts with a rune in scope, so rather than acting like a rune, it will act like a store. So renaming the variable avoids it from acting like a store.
This works as expected. We decided to give stores precedence over runes in this situation. We can revisit this decision in Svelte 6.
It looks like this was a duplicate of #12218. I don't know which one we want to keep.
That issue sounds different to me - I understand it as a request to not reserve the $ prefix
@Conduitry I agree with Simon: my request was to better handle/warn about using "rune-named" variables, whereas the other issue is about allowing $-prefixed variables (which I didn't know was not allowed until now - don't such variables even conflict with stores?).
However, both issues would be solved by disabling some/all impacted runes when a conflicting name is found.
Out of curiosity, how did you come up with this idea of prefixing runes with $? I guess it might have something to do with how reactivity used to work in Svelte, but conflicts with stores and regular $-prefixed variables were inevitable, weren't they?
On the other hand, I can't think of a better way to differentiate runes. Maybe going the Solid way, moving the dollar sign at the end?
Hi there! I'm confused!
I had this problem (with svelte 5.19.9):
const { state } = $props();
const value = $state(''); // CONFLICT with state variable
I was expecting this to be possible.
Why should state collide with $state? It's not the same name...
(I feel like i lack information about the mentioned stores... have a link for me?)
https://svelte.dev/docs/svelte/stores
$foo is an automatically updating variable from the store foo. If foo is present as a variable, then $foo being a store subscription takes precedence over it being a rune. This is to avoid it being a breaking change every time we add a new rune. If someone were using foo and $foo as a store, and we happened to introduce $foo as a rune, it would be a breaking change for them if we started interpreting $foo as a rune.
Ah! Thanks for explanation. Makes sense now.
But could this maybe be bound to a config switch?
That way old project don't break, but new ones can benefit from the improved behavior (when setting the config-flag).
what about renaming variables that need to be protected (like "state") at static analysis time to something like "state_"? wouldn't that solve the problem?
- No need to make special checks when editing code
- Should be simple to do... right? Just analyze variable names before compiling and rename those that are problematic. "state" should be targeted but "$state" should be ignored
- Some codebases happy to be able to use "state" variable names.
Chances are I'm missing something when it comes to it. Maybe targetting these variable names in the static analysis is not so simple after all 😅 just speaking from deep ignorance.
The problem isn't what variables get renamed to in the compiled component. The problem is the store autosubscription thing I mentioned in my comment above.
It's more for Svelte 6, but what about replacing auto-subscription with an explicit subscription via a rune:
let myStoreVal = $store(myStore);
myStoreVal = 42; // equivalent to myStore.set(42);
// or if you prefer
let $myStore = $store(myStore);
This also could be used in *.svelte.ts/js files within the reactive context.
$store looks great, but adding a rune that will ultimately need to be removed in the next few major versions instead of getting rid of stores altogether doesn't sound like a good idea
There is no any talks about removing stores.
Not yet, but they'll very likely get sunset in the next majors