Search code examples
sveltesvelte-5

"This comparison appears to be unintentional" error, why?


I don't know how to reproduce the following in the svelte-5 REPL because it doesn't recognize enum from the same file:

<script lang="ts">
    enum Pro {
        ZERO,
        ONE,
        TWO
    }

    let pros: Pro = $state(Pro.ZERO);

    const again: boolean = $derived(pros == Pro.ONE || pros == Pro.TWO);
</script>

I'm getting the typescript error:

This comparison appears to be unintentional because the types 'Pro.IDLE' and 'Pro.ONE' have no overlap. ts(2367)

Why?


Solution

  • $state is generic, it takes the type of its argument. Since the argument is Pro.ZERO and the declarations of pros and again are executed in the same scope without other assignments to pros, the type for the variable is narrowed via control flow analysis from Pro to Pro.ZERO.

    TS does not know that the derived re-evaluates later with a potentially different value of pros.

    You could either avoid the narrowing via $derived.by or force the type to be less specific via a type assertion.

    let pros = $state(Pro.ZERO) as Pro;
    // or
    let again = $derived.by(() => pros == Pro.ONE || pros == Pro.TWO);
    

    ($derived.by works because now the comparison is in a function and TS cannot infer when the function will be called and hence what value pros will have at that point in time.)