Skip to content

Variable declarations in markup (replacing {@const ...} #16490

@Rich-Harris

Description

@Rich-Harris

Describe the problem

Right now we have {@const ...}, which is a) weird, b) inconsistent with $derived(...), and c) limiting.

Describe the proposed solution

Instead of this...

{#each boxes as box}
  {@const area = box.width * box.height}
  {box.width} * {box.height} = {area}
{/each}

...we could do this:

{#each boxes as box}
  {let area = $derived(box.width * box.height)}
  {box.width} * {box.height} = {area}
{/each}

Or if you want it to be read-only, use const instead. You get the idea.

This would also solve a limitation that people periodically encounter — the fact that you can't create local state. This is particularly irksome if a snippet needs to do something stateful, since you now need to convert it to a component (including carefully moving over any CSS that it uses):

{#snippet counter()}
  {let count = $state(0)}
  
  <button onclick={() => count += 1}>
    clicks: {count}
  </button>
{snippet}

{@render counter()}
{@render counter()}
{@render counter()}

Naturally, $state.raw and $derived.by would also be supported, as would normal non-state declarations. We could also allow declarations with multiple declarators:

{let a = 1, b = 2, c = 3}

Migrating existing uses of {@const ...} in runes-mode components would be trivial...

-{@const x = y}
+{const x = $derived(y)}

...and we could deprecate it at the same time.

This is more powerful, looks nicer, is one less bit of weird non-JavaScript syntax, and is something that would have come in handy a number of times recently.

Scoping would work the same as it does in snippets, i.e. bounded by the parent item (whether that's an element, block or whatever). So this would be possible...

<div>
  {let a = 1}
  {a}
</div>

<div>
  {let a = 1}
  {a}
</div>

...but this would be an error because the declaration is duplicated in the same scope:

<div>
  {let a = 1}
  {a}

  {let a = 1}
  {a}
</div>

Declarations should precede usage. We probably don't want to allow var since it would be confusing to have different scoping rules, and different scoping rules are the only thing that distinguishes var from let.

We probably do want using, at least eventually (see #16192).

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy