最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Svelte 5 dynamic component loading: TypeScript errors - Stack Overflow

programmeradmin0浏览0评论

In my Svelte 4 app I dynamically load components, all of which have different props. Very simple reproduction (also available on the Svelte Playground):

// App.svelte
<script lang="ts">
  import One from "./One.svelte";
  import Two from "./Two.svelte";

  import type { ComponentType } from "svelte";

  type Item = {
    component: ComponentType;
  };

  const items: Item[] = [
    { component: One, one: "World" },
    { component: Two, two: "Svelte" },
  ];
</script>

<div class="container py-20 text-white">
  {#each items as item}
    <div>
      <svelte:component this={itemponent} {...item} />
    </div>
  {/each}
</div>
// One.svelte
<script lang="ts">
    export let one;
</script>

Hello {one}
// Two.svelte
<script lang="ts">
    export let two;
</script>

Goodbye {two}

This works fine without any warnings or errors, no complaints so far. However I want to migrate to Svelte 5 and now I am getting a bunch of TypeScript errors. For example ComponentType is deprecated, and things like this:

Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'ComponentType'.
  Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'new (options: ComponentConstructorOptions<Record<string, any>>) => SvelteComponent<Record<string, any>, any, any>'.
    Types of parameters 'options' and 'options' are incompatible.
      Type 'ComponentConstructorOptions<Record<string, any>>' is not assignable to type 'ComponentConstructorOptions<{ one: any; }>'.
        Property 'one' is missing in type 'Record<string, any>' but required in type '{ one: any; }'.

How can I refactor my code so that it keeps on working, without TypeScript errors, and without having to strongly type each component? In my real-world app there are many components involved, each with a whole bunch of different props. I don't want to have to create type aliases for each of them.

Simply changing ComponentType to Component does get rid of the deprecation warning, but the other warning is still basically the same:

Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'Component<{}, {}, string>'.
  Types of parameters 'props' and 'props' are incompatible.
    Type '{}' is not assignable to type '{ one: any; } & { $$events?: { [evt: string]: CustomEvent<any>; } | undefined; $$slots?: {} | undefined; }'.
      Property 'one' is missing in type '{}' but required in type '{ one: any; }'.ts(2322)

Changing ComponentType to SvelteComponent doesn't make things better either. When I use the unknown type then I get this warning:

Argument of type 'unknown' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent | Component<any, any, any> | null | undefined'.

At least that's only one warning instead of a whole bunch in the array so it's better, but can this really not be solved in a better way (without typing every component)?

In my Svelte 4 app I dynamically load components, all of which have different props. Very simple reproduction (also available on the Svelte Playground):

// App.svelte
<script lang="ts">
  import One from "./One.svelte";
  import Two from "./Two.svelte";

  import type { ComponentType } from "svelte";

  type Item = {
    component: ComponentType;
  };

  const items: Item[] = [
    { component: One, one: "World" },
    { component: Two, two: "Svelte" },
  ];
</script>

<div class="container py-20 text-white">
  {#each items as item}
    <div>
      <svelte:component this={itemponent} {...item} />
    </div>
  {/each}
</div>
// One.svelte
<script lang="ts">
    export let one;
</script>

Hello {one}
// Two.svelte
<script lang="ts">
    export let two;
</script>

Goodbye {two}

This works fine without any warnings or errors, no complaints so far. However I want to migrate to Svelte 5 and now I am getting a bunch of TypeScript errors. For example ComponentType is deprecated, and things like this:

Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'ComponentType'.
  Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'new (options: ComponentConstructorOptions<Record<string, any>>) => SvelteComponent<Record<string, any>, any, any>'.
    Types of parameters 'options' and 'options' are incompatible.
      Type 'ComponentConstructorOptions<Record<string, any>>' is not assignable to type 'ComponentConstructorOptions<{ one: any; }>'.
        Property 'one' is missing in type 'Record<string, any>' but required in type '{ one: any; }'.

How can I refactor my code so that it keeps on working, without TypeScript errors, and without having to strongly type each component? In my real-world app there are many components involved, each with a whole bunch of different props. I don't want to have to create type aliases for each of them.

Simply changing ComponentType to Component does get rid of the deprecation warning, but the other warning is still basically the same:

Type '__sveltets_2_IsomorphicComponent<{ one: any; }, { [evt: string]: CustomEvent<any>; }, {}, {}, string>' is not assignable to type 'Component<{}, {}, string>'.
  Types of parameters 'props' and 'props' are incompatible.
    Type '{}' is not assignable to type '{ one: any; } & { $$events?: { [evt: string]: CustomEvent<any>; } | undefined; $$slots?: {} | undefined; }'.
      Property 'one' is missing in type '{}' but required in type '{ one: any; }'.ts(2322)

Changing ComponentType to SvelteComponent doesn't make things better either. When I use the unknown type then I get this warning:

Argument of type 'unknown' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent | Component<any, any, any> | null | undefined'.

At least that's only one warning instead of a whole bunch in the array so it's better, but can this really not be solved in a better way (without typing every component)?

Share Improve this question edited Nov 20, 2024 at 15:29 Kevin Renskers asked Nov 20, 2024 at 12:07 Kevin RenskersKevin Renskers 5,9805 gold badges58 silver badges121 bronze badges 1
  • 1 @jonrsharpe: The lang- prefix only seems to work for HTML language hints, not fenced code blocks. – brunnerh Commented Nov 20, 2024 at 14:40
Add a comment  | 

1 Answer 1

Reset to default 1

unknown means you have to assert a type first to use it in a meaningful way, if you want to be less strict, you would want any instead:

type Item = {
  component: Component<any>;
  [key: string]: any; // for props
};

const items: Item[] = [
  { component: One, one: "World" },
  { component: Two, two: "Svelte" },
];

(There should be ways to also align the props with the given component type using generics, but that is a bit more complicated.)

In Svelte 5 you also should not use <svelte:component>, you can use the component directly:

<itemponent {...item} />

(Lowercase name is only allowed via the . notation.)

发布评论

评论列表(0)

  1. 暂无评论