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

Svelte组件返回值类型转换与泛型适配技术咨询

解决Svelte+Typesense组件的TypeScript联合类型检查错误

我有一个对接Typesense的Svelte组件,负责将搜索结果返回给父组件,通过插槽实现差异化展示。使用联合类型标注结果返回类型时,出现了以下TypeScript错误:

Property 'price' does not exist on type 'Fruit | Fluid'.
Property 'price' does not exist on type 'Fluid'.ts(2339)

Property 'viscosity' does not exist on type 'Fruit | Fluid'.
Property 'viscosity' does not exist on type 'Fruit'.ts(2339)

Property 'price' does not exist on type 'Highlight<Fruit | Fluid>'.
Property 'price' does not exist on type 'Highlight<Fluid>'.ts(2339)

Property 'viscosity' does not exist on type 'Highlight<Fruit | Fluid>'.
Property 'viscosity' does not exist on type 'Highlight<Fruit>'.ts(2339)

当前仅存在类型检查错误,运行时无异常。我想知道是否可以通过转换组件返回的result变量类型,或者为组件传入指定类型,让它仅返回ExampleResponse<Fruit>或ExampleResponse<Fluid>这类单一类型(实际项目中的类型不止这两种)。

示例代码

main +page.svelte

<script lang="ts">
    import Search from './Search.svelte';
</script>

<Search searchParams="fruit" let:result>
    <div>
        <div>Fruit is {result.document.name}</div>
        <div>Price is {result.document.price}</div>
        <div>Highlighted price is {result.highlight.price.snippet}</div>
    </div>
</Search>

<Search searchParams="fluid" let:result>
    <div>
        <div>Fluid is {result.document.name}</div>
        <div>Viscosity is {result.document.viscosity}</div>
        <div>Highlighted viscosity is {result.highlight.viscosity.snippet}</div>
    </div>
</Search>

Search.svelte

<script lang="ts">
    import { onMount } from 'svelte';

    export let searchParams: 'fruit' | 'fluid';
    let results: ExampleResponse<Fruit | Fluid>[] = [];

    onMount(() => search);

    async function search() {
        // 根据searchParams填充fruit或fluid数据
    }
</script>

{#each results as result}
    <slot {result} />
{/each}

ambient.d.ts

type Fruit = {
    id: string;
    name: string;
    color: string;
    price: number;
};

type Fluid = {
    id: string;
    name: string;
    color: string;
    viscosity: number;
};

type Highlight<T> = {
    [K in keyof T]: HighlightInfo;
};

type HighlightInfo = {
    marked: string;
    snippet: string;
};

type ExampleResponse<T> = {
    document: T;
    highlight: Highlight<T>;
};

我曾尝试在if块中使用in进行类型收窄,虽然有效但只是临时解决方案:

<Search searchParams="fruit" let:result>
    {#if 'price' in result.document && 'price' in result.highlight}
        <div>
            <div>Fruit is {result.document.name}</div>
            <div>Price is {result.document.price}</div>
            <div>Highlighted price is {result.highlight.price.snippet}</div>
        </div>
    {/if}
</Search>

解决方案:为Search组件添加泛型约束

通过给Search组件定义类型映射和泛型,可以让组件根据searchParams的值自动推导返回的ExampleResponse<T>类型,彻底解决类型检查错误。

修改Search.svelte

<script lang="ts">
    import { onMount } from 'svelte';

    // 定义searchParams值与对应文档类型的映射关系
    type SearchTypeMap = {
        fruit: Fruit;
        fluid: Fluid;
        // 后续新增类型直接在此添加键值对即可
    };

    // 约束searchParams为映射类型的键
    export let searchParams: keyof SearchTypeMap;
    // 根据searchParams的类型自动推导results的类型
    let results: ExampleResponse<SearchTypeMap[typeof searchParams]>[] = [];

    onMount(() => search);

    async function search() {
        // 实际请求中可根据searchParams获取对应类型的数据
        // 这里用类型断言保证返回值类型正确
        const response = await fetch(`/api/search?type=${searchParams}`);
        results = await response.json() as typeof results;
    }
</script>

{#each results as result}
    <slot {result} />
{/each}

父组件使用效果

修改后,父组件中使用Search时,TypeScript会自动根据searchParams的值推导result的具体类型,无需额外的类型收窄代码,直接访问专属属性即可通过类型检查:

<Search searchParams="fruit" let:result>
    <div>
        <div>Fruit is {result.document.name}</div>
        <div>Price is {result.document.price}</div>
        <div>Highlighted price is {result.highlight.price.snippet}</div>
    </div>
</Search>

<Search searchParams="fluid" let:result>
    <div>
        <div>Fluid is {result.document.name}</div>
        <div>Viscosity is {result.document.viscosity}</div>
        <div>Highlighted viscosity is {result.highlight.viscosity.snippet}</div>
    </div>
</Search>

扩展说明

  • 新增类型时,只需在SearchTypeMap中添加新的键值对(如vegetable: Vegetable),无需修改其他逻辑
  • 如果需要更灵活的泛型传入,也可以让组件直接接收泛型参数,但类型映射的方式能更好地保证searchParams与返回类型的一致性,避免参数错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:37:03