You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Svelte组件中结合数组属性使用$$Generic?

问题:Svelte中通过属性注入嵌套组件并保持强类型

我需要通过属性注入嵌套组件,同时保持强类型校验。插槽方案不适用,因为没法轻松切换要使用的组件——如果插槽名称支持动态的话倒是可行,但目前并不支持。

最初尝试的问题:$$Generic导致类型统一绑定到首个元素

尝试用$$Generic实现时,数组中所有元素的类型都会基于第一个元素推导,导致后续不同组件的类型报错:

Dynamic.svelte

<script lang="ts">
    import type { ComponentProps, ComponentType, SvelteComponentTyped } from 'svelte'

    type Component = $$Generic<SvelteComponentTyped>
    type ComponentAndProps = {
        component: ComponentType<Component>
        props: ComponentProps<Component>
    }
    export let array: ComponentAndProps[] = []
</script>

{#each array as item}
    <svelte:component this={item.component} {...item.props} />
{/each}

Test.svelte

<script lang="ts">
    import Dynamic from './Dynamic.svelte'
    import A from './A.svelte' // export let a: string
    import B from './B.svelte' // export let b: string
</script>

<Dynamic
    array={[
        {
            component: A,
            props: { a: 'work fine' },
        },
        {
            // ❌ 类型错误:'typeof B__SvelteComponent_' 不能赋值给 'ComponentType<A__SvelteComponent_>'
            component: B,
            props: { b: '' },
        },
        {
            component: A,
            props: { a: 'work fine too'}
        }
    ]}
/>

这里无法单独推导数组中每个元素的props类型,请问有什么解决思路?

解决方案:通过工具函数关联组件与属性

最终我通过一个泛型函数,将组件和对应的props做类型绑定,实现了强类型校验:

utils.ts

import type { ComponentProps, ComponentType } from 'svelte'

export type ComponentAndProps = {
    component: ComponentType
    props: ComponentProps<InstanceType<ComponentType>>
}

export function component<Component extends ComponentType>(
    component: Component,
    props: ComponentProps<InstanceType<Component>>
): ComponentAndProps {
    return { component, props }
}

修改后的Dynamic.svelte

<script lang="ts">
  import type { ComponentAndProps } from '$lib/utils'

  export let array: ComponentAndProps[] = []
</script>

{#each array as item}
  <svelte:component this={item.component} {...item.props} />
{/each}

修改后的Test.svelte

<script lang="ts">
    import { component } from './utils'
    import Dynamic from './Dynamic.svelte'
    import A from './A.svelte' // export let a: string
    import B from './B.svelte' // export let b: string
</script>

<Dynamic
    array={[
        component(A, {a: 'hey'}),
        component(B, {b: 'mom'})
    ]}
/>

扩展:泛型场景的适配

这个方案同样适用于泛型组件场景,比如渲染表格行:

<script lang="ts">
    import type { ComponentAndProps } from './utils'

    type Item = $$Generic
    export let item: Item
    export let fields: ((item: Item) => ComponentAndProps)[]
</script>

{#each fields as field}
    {@const { component, props } = field(item)}
    <svelte:component this={component} {...props} />
{/each}

内容的提问来源于stack exchange,提问作者Jonas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 08:07:46