Skip to content
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

$state(undefined) is typed as never on svelte-check #14435

Open
ykrods opened this issue Nov 26, 2024 · 6 comments
Open

$state(undefined) is typed as never on svelte-check #14435

ykrods opened this issue Nov 26, 2024 · 6 comments

Comments

@ykrods
Copy link

ykrods commented Nov 26, 2024

Describe the bug

On a project generated by [email protected], running a type check to the following code will get a result that p is typed as never.

<script lang="ts">
  type Person = { name: string }

  let p: Person | undefined = $state(undefined)

  $effect(() => {
    // load person
    setTimeout(() => {
      p = { name: "bob" }
    }, 1000);
  });

  let displayName = $derived(p?.name ?? "anon") // => Error: Property 'name' does not exist on type 'never'. (ts)
</script>
<div>{ displayName }</div>

This is considered a bug because it does not occur when the following changes are made.

-  let p: Person | undefined = $state(undefined) // NG
+  let p: Person | undefined = $state() // OK

Reproduction

https://github.com/ykrods/svelte-reproduction-state-type

Logs

$ npm run check

> [email protected] check
> svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json


====================================
Loading svelte-check in workspace: /home/ykrods/work/svelte-reproduction-state-type
Getting Svelte diagnostics...

/home/ykrods/work/svelte-reproduction-state-type/src/App.svelte:13:33
Error: Property 'name' does not exist on type 'never'. (ts)

  let displayName = $derived(p?.name ?? "anon")
</script>


====================================
svelte-check found 1 error and 0 warnings in 1 file

System Info

System:
    OS: Linux 6.10 Manjaro Linux
    CPU: (16) x64 AMD Ryzen 7 5700U with Radeon Graphics
    Memory: 8.43 GB / 14.98 GB
    Container: Yes
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.8.0 - /usr/bin/node
    npm: 10.8.3 - /usr/bin/npm
  Browsers:
    Chromium: 131.0.6778.85
  npmPackages:
    svelte: ^5.1.3 => 5.2.8

Severity

annoyance

@ykrods
Copy link
Author

ykrods commented Nov 26, 2024

I don't know where in the tool chain the problem is, so sorry if this is not the proper place to report it. Thanks for your hard work on Svelte!

@bhuynhdev
Copy link

I believe the correct way to declare types for $state is:

let p = $state<Person | undefined>(undefined);

This will fix it

Unsure why your way errors out though - The Typescript magic works in mysterious way

@dummdidumm
Copy link
Member

From a TypeScript perspective this works as expected, because TypeScript does not see that p is assigned to anything else until it comes across p inside the $derived. Therefore moving the type definition onto the generic fixes this.

@brunnerh
Copy link
Member

brunnerh commented Nov 26, 2024

@ykrods
Copy link
Author

ykrods commented Nov 26, 2024

Thanks for responses!

Based on the received advise, I have confirmed that the following code fixes the error.

let p1 = $state<Person>()
let p2 = $state<Person | undefined>()
let p3 = $state<Person | undefined>(undefined)
let p4: Person | undefined = $state()
let p5: Person | undefined = $state<Person | undefined>(undefined)

@ykrods
Copy link
Author

ykrods commented Nov 27, 2024

Please let me know if it is better to close this issue and discuss it further in another issue.

I understand now that if the type is not specified in generics, an error occurs due to a mismatch between the return type ( Person | undefined ) and the argument type ( undefined ) in the type inference,
so how about define another generics variable for the argument?

As an example, changing the type of $state as follows could also fix the error.

declare function $state<T, U extends T = T>(initial: U): T;

( I am not used to typescript, so I can't judge if there is a problem with the code 💀 )

I think that maintainability, robustness, or other important features should take precedence over this, but I think it is simpler to write a state without explicit generics.

type definition

declare function $state<T>(initial: T): T;
declare function $state<T>(): T | undefined;

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

No branches or pull requests

4 participants