Skip to content

Runes: Introduce an $alias() rune for cleaner access and assignment to nested reactive properties #9290

Open
@Not-Jayden

Description

@Not-Jayden

Describe the problem

Svelte 5's reactivity introduces a requirement for at least one layer deep of nesting when reactive state is defined outside of the top level of a component, and in many cases, will likely have even deeper nested reactive properties. The necessity for nested property access adds a level of verbosity which can make the code less readable and harder to manage.

e.g.

import {dimensions} from './dimensions';

function resetDimensions() {
    dimensions.value.width = 1920;
    dimensions.value.height = 1080;
}

dimensions.value.area = 0; // this will error, as area property does not have a setter

const aspectRatio = $derived(dimensions.value.width / dimensions.value.height);

$effect(() => {
     console.log(`Aspect Ratio changed to ${aspectRatio}`);
})

Describe the proposed solution

Introduce a new rune, $alias(), which enables the creation of new variables from reactive properties and the destructuring of nested reactive properties while retaining reactivity/object property reference. The $alias() rune essentially instructs the compiler to replace variable references with the expanded property access wherever the aliased or destructured variable is referenced, ensuring the reactivity of the original properties is maintained.

The Svelte compiler ideally should issue a warning on attempts to assign to referenced properties that don't have setters, as this is a limitation of assigning primitive values in javascript.

e.g. the example above could instead be writted as:

import {dimensions} from './dimensions';

let { value: { width, height, area } } = $alias(dimensions);

function resetDimensions() {
    width = 1920;
    height = 1080;
}

area = 0;  // Svelte should issue a compiler warning as `dimensions.value.area` does not have a setter. JS can't catch this unfortunately.

const aspectRatio = $derived(width / height);

$effect(() => {
     console.log(`Aspect Ratio changed to ${aspectRatio}`);
})

If desired, you should also be able to create variables using variable assignment instead of destructuring as well. i.e.

let width = $alias(dimensions.value.width);
let height = $alias(dimensions.value.height);
let area = $alias(dimensions.value.area);

Alternatives considered

Some alternative naming has been suggested such as $bind(), $link(), $expose(), or $bridge().

Otherwise the alternative is we continue to require always directly accessing nested properties.

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions