I'm having trouble narrowing types with Tanstack Svelte Query. I am migrating my app from React to Svelte.
My query queryGetMyPageCollection()
returns either an object PageCollection
or false
. PageCollection
has a getPageByPath()
method that returns a Page
object or undefined
.
This is where the problem occurs:
{#if $query.data && $query.data.getPageByPath(data.slug)}
<p>Hooray! We found your page!</p>
<DisplayPage page={$query.data.getPageByPath(data.slug)} />
I am checking $query.data
, which is false
or the PageCollection
object, and, if the object exists, calling getPageByPath()
against the query string to see if we can load a Page
object. If the page object exists, then I display the page in the <DisplayPage>
component.
This code works but TypeScript complains about the <DisplayPage>
line:
Error: Type 'Page | undefined' is not assignable to type 'Page'.
Type 'undefined' is not assignable to type 'Page'. (ts)
However, I know that the getPageByPath()
call for the <DisplayPage>
component will not be undefined because I checked it in the #if
statement.
Similar code works in React, so I'm guessing that in Svelte, TypeScript is not setting the type for the method call in the <DisplayPage>
component based on the #if
statement directly above it.
How do I code this so that TypeScript does not produce an error? Please do not answer "set @tsignore
"; I want to know how to actually solve this the TypeScript/Svelte way.
<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>
{#if $query.data && $query.data.getPageByPath(data.slug)}
<p>Hooray! We found your page!</p>
<DisplayPage page={$query.data.getPageByPath(data.slug)} />
{:else}
<p>On 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>
That should not work in React either, you need to store the result of the function call, otherwise the type will not be narrowed.
E.g. using @const
:
{:else if $query.isSuccess}
<h1>Here is the page</h1>
{@const page = $query.data && $query.data.getPageByPath(data.slug)}
{#if page}
<p>Hooray! We found your page!</p>
<DisplayPage {page} />
{:else}
...