Home > Enterprise >  How to use svelte:component with TypeScript?
How to use svelte:component with TypeScript?

Time:06-08

I would like to use a dynamic component to select a view depending on the value of an enum:

<svelte:component
  this={components[enumValue]}
  {...props}
/>

But I don't get a compile error if I don't pass all the necessary parameters:

<svelte:component
  this={components[enumValue]}
/>

How to correctly specify the typing of dynamic components?


UPD: map example with React

const props: Props = {...}
const components: Record<EnumType, React.FC<Props>> = {
  [EnumType.variant_1]: Component1,
  [EnumType.variant_2]: Component2,
}

CodePudding user response:

You can apply a little indirection using a generic wrapper component. E.g.

<!-- renderer.svelte -->
<script lang="ts">
    import type { SvelteComponentTyped } from 'svelte/internal';

    type C = $$Generic<typeof SvelteComponentTyped<any, any, any>>;

    export let component: C;
    export let props: C extends typeof SvelteComponentTyped<infer P> ? P : never;
</script>

<svelte:component this={component} {...props} />

Usage example:

<!-- adder.svelte -->
<script lang="ts">
    export let a: number;
    export let b: number;
</script>

{a}   {b} = {a   b}
<script lang="ts">
    import Renderer from './renderer.svelte';
    import Adder from './adder.svelte';
</script>

<Renderer component={Adder} />
<!-- Error on "Renderer" because props are missing -->

<Renderer component={Adder} props={{ a: 12 }} />
<!-- Error on "props": Property 'b' is missing in type '{ a: number; }'
                       but required in type '{ a: number; b: number; }' -->

This may require very recent versions of svelte/svelte-preprocess to work correctly with the generics. You could also drop the generics and type the renderer's properties more loosely. Having props as an export of another component at the very least ensures the props missing error.

  • Related