Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to narrow types with Tanstack Svelte query?

Problem

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

        {#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.

Question

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.

Full component code

<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>

>Solution :

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}
    ...
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading