Language-tools: Unexpected Error when Destructing $store Values

Created on 11 Aug 2020  ·  6Comments  ·  Source: sveltejs/language-tools

Describe the bug
The statement $: ({ value } = $store); is valid syntax when value is a property of $store and $store is a Svelte store. It behaves like normal destructuring and is reactive to store updates. This produces an error when lang="ts".

# App.svelte
------------
<script lang="ts">
  import data from "./store";
  $: ({ count } = $data);
</script>
jd:/svelte-playground $ yarn svelte-check                                                                                                                                                                                                                      [0:30]
yarn run v1.22.4
warning package.json: No license field
$ /home/jd/Projects/svelte-playground/node_modules/.bin/svelte-check

Loading svelte-check in workspace: /home/jd/Projects/svelte-playground
Getting Svelte diagnostics...
====================================

/home/jd/Projects/svelte-playground/src/App.svelte:3:9
Error: No value exists in scope for the shorthand property 'count'. Either declare one or provide an initializer. (ts)
;
  $: ({ count } = $data

====================================
svelte-check found 1 error and 0 warnings
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

To Reproduce
1) Start with this REPL: link
2) Download it and add TS support to the project: link
3) Modify App.svelte by adding lang="ts" to the opening <script> tag. (see the above snippet)
4) run svelte-check

Expected behavior
This is valid Svelte/JS syntax and his code runs fine. It should not produce typechecker errors.

Screenshots
If applicable, add screenshots to help explain your problem.
image

System (please complete the following information):

  • OS: Windows
  • IDE: VSCode (Windows-Linux Subsystem)
  • Plugin/Package:

    • Svelte for VSCode

    • svelte-check

    • @tsconfig/svelte

Fixed bug

All 6 comments

Workaround
Don't use destructuring on Svelte stores in Typescript. This is not ideal but not a blocker. It is just less concise when destructuring several properties at once.
REPL: link

# App.svelte
------------
<script lang="ts">
  import data from "./store";
  $: count = $data;
</script>

Of course you can always just refer to the store value directly in the DOM to see reactive updates.

From input

<script lang="ts">
  import data from "./store";
  $: ({ count } = $data);
</script>

<main>
  <h1>Count (inline): {$data.count}</h1>
  <h1>Count (reactive destructure): {count}</h1>
    <button on:click={() => data.update(c => ({count: c.count + 1}))}>
    Increment
  </button>
</main>

svelte2tsx generates the output:

<></>;
import data from "./store";
function render() {


  ;() => {$: ({ count } = __sveltets_store_get(data));}
;
() => (<>

<main>
  <h1>Count (inline): {__sveltets_store_get(data).count}</h1>
  <h1>Count (reactive destructure): {count}</h1>
    <button onclick={() => data.update(c => ({count: c.count + 1}))}>
    Increment
  </button>
</main> </>);
return { props: {}, slots: {}, getters: {}, events: {} }}

export default class extends createSvelte2TsxComponent(__sveltets_partial(render)) {
}

The problem is that the $-assignment is wrapped in a function, so the value does not exist outside of its scope.

we might have to check how the svelte compiler determine when it should declare a variable see if we miss other situation

The problem is the ts AST analysis. It only does the let x = ... transformation if it's a binary expression, but in this case it's a binary expression wrapped inside a parenthized expression.

Edit: I'm in the middle of fixing this - all these if-then-also-think-of-this-corner-case-checks make my mind blurry 😄

Yes, multiple things need to be changed. I'll create a draft PR so you can see my current state.

Was this page helpful?
0 / 5 - 0 ratings