svelte - Eroare TypeScript cu SvelteKit și preluarea datelor din Supabase (Tipul 'null' nu poate fi atribuit tipului 'ArrayLike')


Am un proiect SvelteKit configurat care se autentifică cu supabase. Am folosit acest ghid pentru asta. Autentificarea și preluarea datelor funcționează bine până acum. De fapt, în ceea ce privește aplicația în sine, totul funcționează conform așteptărilor. Doar că primesc o eroare urâtă de Typescript de care nu pot scăpa.

Preiau datele din acest fișier:

// <!-- 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
    };
};

Și fișierul Svelte corespunzător pentru a-l afișa:

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

Acum acestea sunt erorile pe care le primesc:

'pl' is of type 'unknown'.

Și

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

Dar, așa cum am spus, pe pagina web totul se afișează exact cum mă așteptam și nu primesc alte erori, doar că se pare că Typescript nu este mulțumit. Ce este și mai ciudat este că chestia cu data.user.email nu aruncă deloc erori.

Tipurile auto-generate de la supabase arată așa:

// $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
        }
...

Și se pare că sunt deduse corect:

Intellisense arată asta.

Și acesta este fișierul meu 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 {}
    }
}

Căutând eroarea am găsit asta: https://github.com/sveltejs/language-tools/issues/732 și ei vorbesc despre un bug în Typescript, dar eu sunt complet începător în Typescript, așa că nu am nici cea mai mică idee dacă asta are legătură sau ce se întâmplă acolo.

Mă așteptam ca SvelteKit/Typescript să deducă tipurile pentru „data.playlist” din schema mea și în interiorul buclei #each, la fel cum face în interiorul tag-ului script. Nu sunt sigur de ce îmi creează probleme. Mulțumesc că ați citit!

Răspuns #1

Se pare că API-ul supabase poate eventual să returneze null pentru proprietatea data. Nu sunt sigur dacă are sens atunci când selectezi o listă de obiecte, dar dacă tipul spune asta, ai nevoie de o verificare sau de o aserțiune de non-null.

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

// or
return {
    user: session.user,
    playlist: playlist!,
};