如何解决Tanstack Svelte Query中的TypeScript类型收窄问题?
解决Svelte + Tanstack Query中的TypeScript类型收窄问题
问题背景
将应用从React迁移到Svelte时,使用Tanstack Svelte Query遇到类型收窄失效:
- 查询
queryGetMyPageCollection()返回PageCollection | false PageCollection的getPageByPath()方法返回Page | undefined- 模板中已在
#if语句检查$query.data存在且getPageByPath()返回值非空,但TypeScript仍报错<DisplayPage>的page属性接收了undefined类型
错误信息:
Error: Type 'Page | undefined' is not assignable to type 'Page'.
Type 'undefined' is not assignable to type 'Page'. (ts)
原因分析
React的JSX中,TypeScript可以跟踪同一表达式的类型收窄,但Svelte模板的编译逻辑不同:两次调用$query.data.getPageByPath(data.slug)会被视为独立操作,TypeScript无法确认两次调用的返回值完全一致,因此无法自动收窄类型。
正确解决方式
方式一:模板内缓存结果(推荐)
使用Svelte的{#let}指令缓存getPageByPath()的结果,确保只调用一次,让TypeScript能跟踪到类型收窄:
<script lang="ts"> export let data; const query = createQuery({ queryKey: queryKeyUsePages, queryFn: async () => queryGetMyPageCollection() }); </script> <div> {#if $query.isLoading} <p>Loading...</p> {:else if $query.isError} <p>Error: {$query.error.message}</p> {:else if $query.isSuccess} <h1>Here is the page</h1> {#let foundPage = $query.data ? $query.data.getPageByPath(data.slug) : undefined} {#if foundPage} <p>Hooray! We found your page!</p> <DisplayPage page={foundPage} /> {:else} <p>Oh no! We didn't find your page.</p> {#if $query.data} <p>Available paths:</p> <ul> {#each $query.data.pages as page} <li><a href="/{page.path}">{page.title}</a></li> {/each} </ul> {/if} {/if} {/let} {/if} </div>
方式二:在Script中派生可读存储
如果需要在多个地方复用该结果,可以创建一个派生的可读存储,提前处理类型收窄:
<script lang="ts"> import { derived } from 'svelte/store'; export let data; const query = createQuery({ queryKey: queryKeyUsePages, queryFn: async () => queryGetMyPageCollection() }); // 派生存储,自动处理类型收窄 const foundPage = derived(query, ($query) => { if (!$query.data || $query.status !== 'success') return undefined; return $query.data.getPageByPath(data.slug); }); </script> <div> {#if $query.isLoading} <p>Loading...</p> {:else if $query.isError} <p>Error: {$query.error.message}</p> {:else if $query.isSuccess} <h1>Here is the page</h1> {#if $foundPage} <p>Hooray! We found your page!</p> <DisplayPage page={$foundPage} /> {:else} <p>Oh no! We didn't find your page.</p> {#if $query.data} <p>Available paths:</p> <ul> {#each $query.data.pages as page} <li><a href="/{page.path}">{page.title}</a></li> {/each} </ul> {/if} {/if} {/if} </div>
说明
两种方式核心都是避免重复调用可能返回undefined的方法,通过缓存或提前计算的方式让TypeScript明确知道变量的类型,从而消除错误。
内容的提问来源于stack exchange,提问作者Patrick Kenny
相关产品推荐
相关产品推荐

