Repository: sveltejs/svelte (JavaScript)
Date: 2017-04-12 22:58:12+00:00
Task type: Feature

Issue:
Change missing property errors to warnings?
After upgrading to the latest version of Svelte I was met with a bunch of `Component was created without expected data property 'whatever'` errors that broke my application.

It is not a huge amount of work to set default values for the properties using the `data()` method, but I personally liked that previously you could do things like this where your component can be hidden by default until you explicitly `set({ show : true })` on it:

```html
<div class="something{{ show ? ' show' : '' }}">Hello</div>
```

I find it convenient to not have to pass `show="false"` when initializing the component. I think for an outsider coming to svelte for the first time they would expect it to work the same way as I did (any property you reference is treated as `undefined` until you set a value to it) just cause that is how variable values and object properties work in javascript in general.

Anyway I think it would make sense to change this to a warning instead of breaking your whole application.


Issue discussion:
Yep — I think it makes sense for this to be a warning
If you have a lot of components where you don't initially declare a data property, you'll lose out in terms of performance since the shape of the state object changes after it's initially created.
On a somewhat related note, I just noticed this:

```javascript
if ( !( 'Math' in this._state ) ) { throw new Error( "Component was created without expected data property 'Math'" ); }
```

With a component where I am doing  `style="{{ Math.max(0, somethingElse) }}"`. I can’t reproduce in the REPL though, does that run in dev mode?

---

That one shouldn’t even be throwing a warning :smile:
Good point, that's a bug. It should ignore the whitelisted globals. No, the REPL doesn't run in dev mode — issue here: https://github.com/sveltejs/svelte.technology/issues/45

Agree on the performance point, though I don't think that's a good enough reason to *force* users into doing it, I think a warning is probably still appropriate.
@PaulBGD in a lot of my cases I **want** the component to change after it is created. For example I may have a component containing an SVG where the path I’m drawing requires some additional data to be calculated asynchronously. So I have been rendering the component and then after the data is available (after making an ajax call or what have you), I am updating the state to include the extra data. I admit that is probably not a common thing.

@Rich-Harris do you want me to make a separate ticket for the `Math` error?

Solution patch:
diff --git a/src/generators/Generator.js b/src/generators/Generator.js
--- a/src/generators/Generator.js
+++ b/src/generators/Generator.js
@@ -148,7 +148,9 @@ export default class Generator {
 		});
 
 		dependencies.forEach( name => {
-			this.expectedProperties.add( name );
+			if ( !globalWhitelist.has( name ) ) {
+				this.expectedProperties.add( name );
+			}
 		});
 
 		return {
diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js
--- a/src/generators/dom/index.js
+++ b/src/generators/dom/index.js
@@ -218,7 +218,7 @@ export default function dom ( parsed, source, options ) {
 	if ( options.dev ) {
 		generator.expectedProperties.forEach( prop => {
 			constructorBlock.addLine(
-				`if ( !( '${prop}' in this._state ) ) throw new Error( "Component was created without expected data property '${prop}'" );`
+				`if ( !( '${prop}' in this._state ) ) console.warn( "Component was created without expected data property '${prop}'" );`
 			);
 		});
 


Test patch:
diff --git a/test/runtime/samples/dev-warning-missing-data-binding/_config.js b/test/runtime/samples/dev-warning-missing-data-binding/_config.js
--- a/test/runtime/samples/dev-warning-missing-data-binding/_config.js
+++ b/test/runtime/samples/dev-warning-missing-data-binding/_config.js
@@ -1,7 +1,7 @@
 export default {
 	dev: true,
 
-	error ( assert, err ) {
-		assert.equal( err.message, `Component was created without expected data property 'value'` );
-	}
-};
\ No newline at end of file
+	warnings: [
+		`Component was created without expected data property 'value'`
+	]
+};
diff --git a/test/runtime/samples/dev-warning-missing-data/_config.js b/test/runtime/samples/dev-warning-missing-data/_config.js
--- a/test/runtime/samples/dev-warning-missing-data/_config.js
+++ b/test/runtime/samples/dev-warning-missing-data/_config.js
@@ -1,7 +1,8 @@
 export default {
 	dev: true,
 
-	error ( assert, err ) {
-		assert.equal( err.message, `Component was created without expected data property 'foo'` );
-	}
-};
\ No newline at end of file
+	warnings: [
+		`Component was created without expected data property 'foo'`,
+		`Component was created without expected data property 'bar'`
+	]
+};
diff --git a/test/runtime/samples/dev-warning-missing-data/main.html b/test/runtime/samples/dev-warning-missing-data/main.html
--- a/test/runtime/samples/dev-warning-missing-data/main.html
+++ b/test/runtime/samples/dev-warning-missing-data/main.html
@@ -1 +1,4 @@
-<p>{{foo}}</p>
\ No newline at end of file
+<p>
+	{{Math.max(0, foo)}}
+	{{bar}}
+</p>