Repository: sveltejs/svelte (JavaScript)
Date: 2020-03-04 20:14:12+00:00
Task type: Feature

Issue:
Throw a warning if we are declaring a variable with const and also using bind directive to mutate its value. 
**Is your feature request related to a problem? Please describe.**
While defining a variable in #Svelte, make sure to use let/var and not const, otherwise those bindings won't work, as it can't be updated by its compiler. 
![image](https://user-images.githubusercontent.com/34736432/75478324-c82b5800-59c3-11ea-908d-0b941c81969e.png)


**Describe the solution you'd like**
Throw a warning or error.

**Describe alternatives you've considered**
Using let always.

**How important is this feature to you?**
It brings a delight to users.




Issue discussion:
This sounds reasonable. I think I'd favor an outright compilation error in this case. We need to be careful though because binding to `foo.bar` when `foo` is a const should continue to be valid.
Yes absolutely. Making sure that primitives cannot be mutated once assigned with const. Sounds reasonable?
Some pointers for getting started on the **good first issue**:
1. Read our [Contribution Guide](https://github.com/sveltejs/svelte/blob/master/CONTRIBUTING.md)
1. We checked whether the `bind:` variable is defined or not [here in `src/compiler/compile/nodes/Binding.ts`](https://github.com/sveltejs/svelte/blob/527ddea289196f3dc4c8ca5e0d001b9c7e5ce2a0/src/compiler/compile/nodes/Binding.ts#L67-L72)
    - You can add another check to see whether the variable can be mutated.
    - Exhaustive list of the properties of the variables can be found in the [`vars` section of the doc](https://svelte.dev/docs#svelte_compile)
1. tests for compile time validation goes into the `test/validator/` folder (you can refer to [this test sample](https://github.com/sveltejs/svelte/tree/b1d919f3f28e1d316328248c0b7047d4514483cf/test/validator/samples/binding-invalid-value))


Solution patch:
diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts
--- a/src/compiler/compile/nodes/Binding.ts
+++ b/src/compiler/compile/nodes/Binding.ts
@@ -72,6 +72,11 @@ export default class Binding extends Node {
 			});
 
 			variable[this.expression.node.type === 'MemberExpression' ? 'mutated' : 'reassigned'] = true;
+
+			if (info.expression.type === 'Identifier' && !variable.writable) component.error(this.expression.node, {
+				code: 'invalid-binding',
+				message: 'Cannot bind to a variable which is not writable',
+			});
 		}
 
 		const type = parent.get_static_attribute_value('type');


Test patch:
diff --git a/test/validator/samples/binding-const-field/errors.json b/test/validator/samples/binding-const-field/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/binding-const-field/errors.json
@@ -0,0 +1 @@
+[]
diff --git a/test/validator/samples/binding-const-field/input.svelte b/test/validator/samples/binding-const-field/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/binding-const-field/input.svelte
@@ -0,0 +1,7 @@
+<script>
+	const dummy = {
+		foo: 'bar'
+	};
+</script>
+
+<input bind:value={dummy.foo}>
diff --git a/test/validator/samples/binding-const/errors.json b/test/validator/samples/binding-const/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/binding-const/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "invalid-binding",
+	"message": "Cannot bind to a variable which is not writable",
+	"pos": 61,
+	"start": {
+		"line": 5,
+		"column": 19,
+		"character": 61
+	},
+	"end": {
+		"line": 5,
+		"column": 24,
+		"character": 66
+	}
+}]
\ No newline at end of file
diff --git a/test/validator/samples/binding-const/input.svelte b/test/validator/samples/binding-const/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/binding-const/input.svelte
@@ -0,0 +1,5 @@
+<script>
+	const dummy = 'foo';
+</script>
+
+<input bind:value={dummy}>