Skip to content

Svelte 5: Composable components, {@render ...} throws type errors whether it is a Component or Snippet type. #15128

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
robertkibet opened this issue Jan 28, 2025 · 1 comment

Comments

@robertkibet
Copy link

Describe the bug

Building Composable components is problematic with TypeScript. Slots used to work well, the new {@render ...} method seems to cause some Type errors with Snippets/Component types 🤔

// Button.svelte file
<script lang="ts">
  import type { Component } from 'svelte';

 type ButtonProps = {
    text?: string;
    icon?: Component;
  };

  let {icon, text}:ButtonProps = $props()
</script>

<div class="content">
  {#if icon}
    {@render icon()}
  {/if}
  {text}
</div>

Above code snippet throws a type error:

/home/projects/svelte-render-component-type/src/lib/Button.svelte:14:14
Error: Argument of type '{ $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial<{}>): void; }' is not assignable to parameter of type '{ '{@render ...} must be called with a Snippet': "import type { Snippet } from 'svelte'"; } & unique symbol'.
Property ''{@render ...} must be called with a Snippet'' is missing in type '{ $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial<{}>): void; }' but required in type '{ '{@render ...} must be called with a Snippet': "import type { Snippet } from 'svelte'"; }'. (ts)

And if I update the type to use Snippets, it still throws an error, the error is now thrown in the parent component

// Button.svelte file
<script lang="ts">
  import type { Snippet } from 'svelte';

 type ButtonProps = {
    text?: string;
    icon?: Snippet;
  };

  let {icon, text}:ButtonProps = $props()
</script>

<div class="content">
  {#if icon}
    {@render icon()}
  {/if}
  {text}
</div>
// App.svelte file throws a type error
<Button text="I can accept props" icon={CustomIcon} />

The type error thrown is this:

/home/projects/svelte-render-component-type/src/App.svelte:11:39
Error: Type '__sveltets_2_IsomorphicComponent<{ [x: string]: never; }, { [evt: string]: CustomEvent; }, {}, {}, string>' is not assignable to type 'Snippet<[]>'.
Target signature provides too few arguments. Expected 2 or more, but got 0. (ts)

Previously in Svelte v4 I would just use <svelte:component this={icon} /> and it would work well.
Ref: https://svelte.dev/docs/svelte/v5-migration-guide#svelte:component-is-no-longer-necessary

Reproduction

Please fork and test this stackblitz project: https://stackblitz.com/edit/svelte-render-component-type?file=src%2Flib%2FButton.svelte

Steps:

  • Access the terminal
  • run npm check
  • you should see the type errors

Logs

System Info

~/projects/svelte-render-component-type 24s
❯ npx envinfo --system --npmPackages svelte,rollup,webpack --binaries --browsers
Need to install the following packages:
envinfo@7.14.0
Ok to proceed? (y) y

  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    svelte: ^5.19.3 => 5.19.3

Severity

annoyance

@robertkibet robertkibet changed the title Svelte 5: Composable components, {@render ...} throws type errors whether it is a Component or Snippet type. <svelte:component this={icon} /> work in this example. Svelte 5: Composable components, {@render ...} throws type errors whether it is a Component or Snippet type. Jan 28, 2025
@brunnerh
Copy link
Member

Components and snippets are not interchangeable, if you want to pass a component as snippet, you have to explicitly create one that wraps the component.

// App.svelte file throws a type error
- <Button text="I can accept props" icon={CustomIcon} />
+ <Button text="I can accept props">
+   {#snippet icon}<CustomIcon/>{/snippet}
+ </Button>

Related issue:

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

3 participants