Skip to content

Allow let in reactive variable declarations #4965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
benmccann opened this issue Jun 3, 2020 · 14 comments
Closed

Allow let in reactive variable declarations #4965

benmccann opened this issue Jun 3, 2020 · 14 comments

Comments

@benmccann
Copy link
Member

benmccann commented Jun 3, 2020

Is your feature request related to a problem? Please describe.
The TypeScript preprocessor does not yet fully support reactive statements, which makes it difficult to use TypeScript with Svelte.

There's an open question of how Svelte's syntax should be included in TypeScript. This is essentially a new syntax that needs to be spec'd out.

Describe the solution you'd like

It would be natural to do something like:

$: let squared: number = num * num;
$: let cubed: number = squared * num;

However, Svelte does not support let in reactive statements today.

Describe alternatives you've considered
Potentially we could find the first time a reactive variable used in the preprocessor and insert the let before passing it to TypeScript. However, this is sort of against the spirit of TypeScript, which expects some extra verbosity from the user in exchange for extra error checking such as checking whether you're referencing an undeclared variable.

I see no harm in allowing regular JS users to do:

$: let squared = num * num;
$: let cubed = squared * num;

How important is this feature to you?
TypeScript support in general is very important to myself and the community. Whether this is the best way to implement support or not is TBD.

Additional context

I think that the Svelte team should weigh in here on how we want this to work even if it's not this syntax. It doesn't seem right to me that the preprocessor would be in charge of deciding because then you could end up with a different syntax in each preprocessor and language-tools/VSCode might not know how to handle the syntax.

I believe that the preprocessor doesn't currently use the AST or do anything sophisticated and that the Svelte compiler is already tracking whether a variable usage is the first and should be a declaration or not. As a result, it would probably be easiest to implement in the Svelte compiler (for someone familiar with the Svelte compiler code. For someone new to the codebase that's probably flipped because the Svelte codebase is larger and more complicated in general.)

@pushkine
Copy link
Contributor

pushkine commented Jun 3, 2020

label: let is invalid javascript

@benmccann
Copy link
Member Author

Yeah, but Svelte isn't interpreted as JavaScript, but rather compiled to JavaScript and then interpreted, right?

@kevmodrome
Copy link
Contributor

Svelte being very close to JS makes other tooling work easily with it. If you add too much non-standard things you'll likely run into problems.

@benmccann
Copy link
Member Author

The only tooling I'm aware of are the preprocessors and language-tools and I'm specifically proposing this to make it easier for that tooling to deal with in this case. Is there other tooling I might be overlooking?

I'm totally open to suggestions though on what the preferred syntax for reactive variables in TypeScript should be if you have ideas

@Conduitry
Copy link
Member

Having the <script> tag be at least parseable as normal javascript is currently one of the non-negotiable aspects of Svelte's syntax. We don't have the resources to maintain a fork of Acorn or to support this in all of the different tooling and syntax highlighting and so on. If non-JS syntax was allowed in script tags, I'd probably bail on maintaining the official ESLint plugin, for example.

@BillyLevin
Copy link
Contributor

i believe it still has to be valid JavaScript, it just gets compiled to different JavaScript, for example to give labelled statements different behaviour

svelte uses an ESTree compliant parser, so i don't think this would be possible to do, or at least it would require a lot of changes (probably a custom parser?). you'll probably need to come up with a valid JS syntax that's as obscure as labelled statements to use for this

@benmccann
Copy link
Member Author

benmccann commented Jun 3, 2020

Ahh, okay. I didn't think about it from the parsing angle. That's super helpful. Thanks! It sounds like it would be much better to handle in the preprocessor in this case.

I'm not quite sure what they best syntax is here. There's something we have to invent for the intersection of Svelte and TypeScript.

Without let, but with typing, would be most similar to Svelte:

$: squared: number = num * num;
$: cubed: number = squared * num;

Having or allowing users to use let would be most similar to TypeScript and thus easiest to implement in the preprocessor since we're passing it to TypeScript first:

$: let squared: number = num * num;
$: let cubed: number = squared * num;

Neither would be valid TypeScript, JS, nor Svelte, but there's not much syntax that would be when you have both Svelte and TypeScript in the mix.

I'm still curious what you all think even if we're implementing purely in the pre-processor because I don't want to go off and invent our own non-blessed syntax more than necessary.

@pushkine
Copy link
Contributor

pushkine commented Jun 3, 2020

let squared: number;
$: squared = num * num;

@benmccann
Copy link
Member Author

That could be an option. I do like that we wouldn't be having to come up with additional syntax in that case. Though it is more verbose to have to split declaration and initialization into two separate lines. I think the biggest drawback is that it's somewhat unexpected by users to need two lines in this scenario.

Regardless of which route we go with, we should document it somewhere since there's nowhere that explains it yet. The TypeScript question in the FAQ would be one place we could put it. I think this is the only syntax that really needs any explanation since it's the only place where Svelte does something you wouldn't normally do in Vanilla JS or TypeScript.

@MrSrsen
Copy link

MrSrsen commented Jun 5, 2020

There was already similar discussion regarding TypeScript syntax in the #4518 .

@benmccann
Copy link
Member Author

Thanks for the pointer!

@GrygrFlzr
Copy link
Member

@AradAral Type inference works with the appropriate configuration, but was not the point of the issue. Consider the following snippet:

const something = 200;
$: myString = something;

Which will infer that myString is a number, versus this JSDoc annotation with checkJs: true

const something = 200;
/** @type {string} */
let myString;
$: myString = something;

or the TypeScript equivalent:

const something = 200;
let myString : string;
$: myString = something;

The type annotation guards against incorrectly assigning incompatible types:

Type 'number' is not assignable to type 'string'.

Editor suggestions are only part of the reason for having type information.

@phocks
Copy link

phocks commented Mar 3, 2022

$: myString = something as string;

Appears to work? It declares the variable and casts it as a string.

Equivalent to

let myString: string = something;

Except reactive, as far as I can tell.

@dev-msp
Copy link

dev-msp commented May 24, 2022

Casting a value to a certain type is not equivalent to associating a type with a variable name. Treating the two as equivalent is likely to introduce downstream typing issues.

let myString: string = EXPRESSION is like asking the compiler whether EXPRESSION is a string. Compiler has the final say.

myString = something as string is like telling the compiler what myString is, and it will accept whatever you give it, even if the type doesn't match the value. Developer has the final say here, not the compiler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants