Search code examples
typescriptsveltesveltekitsupabase

Typescript error with SvelteKit and Supabase data fetching (Type 'null' is not assignable to type 'ArrayLike<unknown>')


I have a SvelteKit project set up which authenticates with supabase. I used this guide for that. The authentication and data fetching works fine so far. Actually, in terms of the app itself, everything works as expected. I’m just getting a nasty Typescript error which I can’t get rid of.

I’m fetching the data in this file:

// <!-- routes/playlists/+page.ts -->

import type { PageLoad } from './$types';
import { redirect } from '@sveltejs/kit';

export const load: PageLoad = async ({ parent }) => {
    const { supabase, session } = await parent();
    if (!session) {
        throw redirect(303, '/');
    }

    const { data: playlist } = await supabase.from('playlist').select('*');

    return {
        user: session.user,
        playlist
    };
};

And the corresponding svelte file to display it:


<!-- routes/playlists/+page.svelte -->

<script lang="ts">
    import type { PageData } from './$types';
    import { json } from '@sveltejs/kit';
    export let data: PageData;
</script>

<main>
    <div>{data.user.email}</div> <!-- This works fine! -->

    <ul>
        {#each data.playlist as pl}  <!-- Typescript complains about this -->
            <li>
                {pl.spotify_uri}  <!-- and this -->
            </li>
        {/each}
    </ul>
</main>

Now these are the errors I’m getting:

'pl' is of type 'unknown'.

And

Argument of type '{ created_at: string; follower_count: number; last_auto_renewal: string; last_manual_renewal: string; playlist_id: number; spotify_uri: string; user_id: string | null; }[] | null' 
is not assignable to parameter of type 'ArrayLike<unknown>'.

Type 'null' is not assignable to type 'ArrayLike<unknown>'.

But, as I said, on the webpage everything is displayed just as expected & I’m getting no other errors, it just seems that Typescript isn’t happy. What’s also weird is that the data.user.email thing throws no errors at all.

The auto-generated types from supabase look like this:

// $lib/supabase/schema.ts

export interface Database {
  public: {
    Tables: {
      playlist: {
        Row: {
          created_at: string
          follower_count: number
          last_auto_renewal: string
          last_manual_renewal: string
          playlist_id: number
          spotify_uri: string
          user_id: string | null
        }
...

And they seem to get inferred correctly:

Intellisense shows this.

And this is my app.d.ts:

import { SupabaseClient, Session } from '@supabase/supabase-js';
import { Database } from '$lib/supabase/schema';

declare global {
    namespace App {
        interface Locals {
            supabase: SupabaseClient<Database>;
            getSession(): Promise<Session | null>;
        }
        interface PageData {
            session: Session | null;
        }
        // interface Error {}
        // interface Platform {}
    }
}

When searching for the error I found this: https://github.com/sveltejs/language-tools/issues/732 and they talk about some bug in Typescript, but I’m a total Typescript beginner so I have no idea if this is related or what’s going on there.

I expected SvelteKit/Typescript to infer the types for "data.playlist" from my schema within the #each loop as well, just like it’s doing within the script tag. Not sure why it’s giving me trouble. Thanks for reading!


Solution

  • Sounds like the supabase API can possibly return null for the data property. Not sure if that makes sense when selecting a list of objects, though, but if the type says so, you need a guard or not-null assertion.

    const { data: playlist } = ...
    if (playlist == null)
      throw ...; // or make it a `let` and assign an empty array? 
    
    // or
    return {
        user: session.user,
        playlist: playlist!,
    };