-
-
Notifications
You must be signed in to change notification settings - Fork 53
Description
Motivation
const
in javascript:
The const declaration creates an immutable reference to a value.
It does not mean the value it holds is immutable — just that the variable identifier cannot be reassigned.
You should understand const declarations as "create a variable whose identity remains constant", not "whose value remains constant" — or, "create immutable bindings", not "immutable values".https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
At the moment the Svelte 5 compiler breaks this rule and we can no longer make assumptions of what should be possible.
<script>
const { value } = $props()
const copy = value;
console.log(value) // output: 1
function onclick() {
console.log(value) // output: 3 (prop was updated)
if (copy === value) { // false ?!?
}
}
</script>
<button {onclick}>Click me</button>
Because the compiler replaces all usages of reactive values by getters & setters, this doesn't result in aTypeError: Assignment to constant variable.
error like it would in regular javascript.
Description
The svelte/rune-prefer-let rule is aware of which variables are reactive by detecting switch are assigned via a rune.
eslint prefer-const
rule doesn't see any reassignments so it assumes a let statement can be safely converted to const
which conflicts with the svelte/rune-prefer-let
The svelte/prefer-const rule is identical, but takes into account which variable are reactive an can be reassigned.
Examples
<!-- ✓ GOOD -->
<script>
let {count, onclick} = $props();
let double = $derived(count * 2);
</script>
<!-- ✗ BAD -->
<script>
const {count, onclick} = $props();
const double = $derived(count * 2);
</script>
Activity
ota-meshi commentedon Sep 13, 2024
The code doesn't change the variables, so I think it's fine to use
const
. Is it really necessary to uselet
? 🤔They work in runes, so it makes sense that they don't match the description on MDN.
I prefer to use
const
since it is necessary to completely prohibit reassignment of variables using$derived
.mrh1997 commentedon Sep 13, 2024
@ota-meshi : Although I absolutely can follow your argumentation please keep in mind that this is not what people will intuitively do.
Thus if you stick to your approach all tutorials should be adopted and eslint should at least output a message which tells the user to use "const" when working with "$derived".
ota-meshi commentedon Sep 13, 2024
I don't force my preferred code style on other people's projects.
mrh1997 commentedon Sep 13, 2024
I don't think this issue is a question of code style. Changing code style will never break code. But switching between "let" and "const" does (or at least make the linter not accept the code any more).
What I meant: whatever decision the svelte core team mets: please keep in mind to stay consistent here...
bfanger commentedon Sep 15, 2024
The variable is reassigned by code, but not by your code.
Something that should be impossible at runtime for const.
It is not necessary. Using either let or const the Svelte compiler will not allow you to reassign a $derived variable.
You'll get a
Cannot assign to derived state
error in your editor/build.In a way, const is not necessary either.
When replacing all const statements with let in a codebase, the code will "work" but these variables no longer throw runtime errors when reassigned.
Replacing all let variables that are not reassigned will also "work".
But I prefer to use const for variables that are not reassigned.
That the job of the author of a ESLint config, but as a ESLint plugin maintainer you play a rule in forcing a preferred code style.
There are two views:
let
means "this variable can be reassigned"const
to mean "this variable cannot be reassigned" not by me, not by anyone.let
means "this variable can be reassigned"const
to mean "this variable can reassigned by Svelte but not by me".I am in 1, I want
const
to mean the same as it does the rest of JavaScript.Some are in 2 and prefer to use const for $derived because for them it better communicates that this is a readonly value, not necessarily that the value itself never changes and they want to use const for components that only have readonly props.
The issue is that regular ESLint only caters to view 2, creates incorrect code for view 1.
Rules like
prefer-const
are not aware of Svelte's transformations to the code. This is whatsvelte/prefer-const
solves.ota-meshi commentedon Sep 18, 2024
Thank you for explaining, I hadn't thought of it that way.
I think it would be a good idea to add rules for users who prefer
1.
.Perhaps those users would want to define variables that are not reassigned other than
$derived()
and$props()
asconst
, and the rest aslet
, so I think it might be convenient to provide it in a single rule. What do you think?Also, the documentation for those rules should include a note that they conflict with
prefer-const
.MathiasWP commentedon Oct 22, 2024
I'm having the same problem in a component with bindable properties.
If i set
const { ... } = $props()
then my code triggers aCannot assign to X because it is a constant.
on the bindable properties, and if i change it tolet { ... } = $props()
then the ESLint prefer-const rule is triggered :/mikededo commentedon Nov 28, 2024
Hey @MathiasWP and @ota-meshi, I'll be continuing @bfanger's work in another PR. I think this rule would be helpful in many cases, despite being opinionated and Svelte not strictly defining how it should be done.
mikededo commentedon Nov 28, 2024
After having worked on this for a bit, how do you feel about adding another property to the rule that would allow devs to prevent reactive declarations from Svelte to be checked by this rule?
For instance, I like having my
derived
andprops
as const, therefore I'd only wantstate
and it's variants to be checked. Currently the rule as implemented in #933, it checks for all reactive assignments. So I'm thinking something like:So:
Just throwing this as an idea, which would allow more granular configuration.
mikededo commentedon Nov 29, 2024
Also, the rule should also work for
*.svelte.{js,ts}
files, right?KieranP commentedon Dec 20, 2024
I'm in the same boat as @MathiasWP . Upgrading my app to Svelte 5. In most places, I use const for my $props without issue. But if it includes $bindable, then I need to use let. But then eslint complains that non-bindables in the $props should be const. And unfortunately, Svelte does not support calling $props twice. So the only solution is to use let for $props, and add
// eslint-ignore-next-line prefer-const
before each prop that should be a const.Ideally Svelte would support this:
But short of that, the prefer-const linter should skip over a $props call when $props contains a bindable.
MathiasWP commentedon Dec 21, 2024
I would recommend setting the prefer-const rule to "warn" instead of "error", so that you don't have to add the comment every time for lint to pass, but you can easily find the places in your code where this happens.
KieranP commentedon Dec 24, 2024
@MathiasWP Thanks for the recommendation. I want this enforced in all other areas of my codebase however. I can turn the rule to warning for Svelte files as a whole, but then I can use let elsewhere in the file without error. I would be great if eslint could disable for specific statements (i.e. $props()). For now, I'll need to keep using the eslint-disable-next-line comment
mikededo commentedon Dec 31, 2024
@MathiasWP and @KieranP, the
prefer-const
rule is already available.KieranP commentedon Dec 31, 2024
@mikededo Great news, thanks. Now just need to wait for v3.0.0 to be released :-)
baseballyama commentedon Dec 31, 2024
For now, we can use 3.0.0-next.9.
It will take some more time before v3.0.0 is released. Some breaking changes have already been introduced, but you/we should be able to address them by looking at the CHANGELOG. (Eventually, this will be documented.)
justingolden21 commentedon Jan 4, 2025
I've got dozens of these and it's crowding me from seeing my actual legitimate errors. Some props are const and some change, so I can't just destructure as const. I also can't split into 2 destructures (which is also hideous and impairs readability) because $bindable needs to be inside a props declaration
EDIT: worth mentioning I have
prefer-const
set to error in my eslint config mjs. I'd like to keep this on, which is why I set it there, so I declare unchanging variables as const which prevents me from accidentally changing them, but unfortunately I have to turn it off for now.baseballyama commentedon Jan 4, 2025
Please upgrade the plugin to 3.0.0-next.10 and disable
prefer-const
and enablesvelte/prefer-const
.excludedRunes
option to theprefer-const
rule #1064Back
button to Svelte 5 dfinity/gix-components#631ESLint : désactivation des règles prefer-const et svelte/prefer-const
Disable prefer-const for Svelte for now