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.
System (please complete the following information):
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.