Search code examples
typescriptnext.jsnext.js13supabasesupabase-database

TypeScript: "Type is not assignable to type 'never'" with Conditional Types in Supabase Query


Question

I am working on a Next.js project using Supabase for the backend. I have defined some helper types to handle the responses from Supabase queries, but I'm running into a TypeScript issue that I can't seem to resolve.

Helper Types:

Here are my helper types and a brief description of each:

  • DbResult<T>: This type is intended to unwrap the type from a promise. If T is a promise, it infers the type U that the promise resolves to.

  • DbResultOk<T>: This type is meant to handle successful query results. It infers the data field from the promise and excludes null values.

  • DbResultErr: This type is simply an alias for PostgrestError, intended to handle errors from the Supabase query.

export type DbResult<T> = T extends PromiseLike<infer U> ? U : never;
export type DbResultOk<T> = T extends PromiseLike<{ data: infer U }> ? Exclude<U, null> : never;
export type DbResultErr = PostgrestError;

Code:

I am using these types in a function that performs a Supabase query:

export async function addFrequentIngresoAccion(payload: {
  // ... payload definition
}): Promise<DbResult<any>> {
  const supabase = createServerActionClient<Database>({ cookies });
  const query = supabase.from("FuenteIngreso").insert([/*...*/]).select();
  const result: DbResult<typeof query> = await query;

  if (result.error) {
    const resultErr: DbResultErr = result.error;
    return { error: resultErr };
  }

  const resultOk: DbResultOk<Tables<"FuenteIngreso">[]> = result.data as Tables<"FuenteIngreso">[];
  return { data: resultOk };
}

The line const resultOk: DbResultOk<Tables<"FuenteIngreso">[]> = result.data as Tables<"FuenteIngreso">[]; is throwing the following error:

Type '{ CantidadIngresoRecurrente: number | null; created_at: string; es_recurrente: boolean | null; fechadepositorecurrente: string | null; fuente_name: string; id: number; LastIngresoAdded: string | null; user_id: string; }[]' is not assignable to type 'never'.ts(2322)

I don't understand why the type is falling back to never. Can anyone help me understand what's going wrong here? Also, if my understanding of the helper types is incorrect, please feel free to correct me.


Solution

  • I literally just encountered this exact issue today... what are the odds. For me it was the return value of a Supabase Postgres Function and not a table but I think the change should be exactly what you need or close enough.

    Change this line:

    const resultOk: DbResultOk<Tables<"FuenteIngreso">[]> = result.data as Tables<"FuenteIngreso">[];
    

    to this:

    const resultOk: DbResultOk<typeof query> = result.data
    

    Why this change?

    DbResultOk is defined as this:

    export type DbResultOk<T> = T extends PromiseLike<{ data: infer U }> ? Exclude<U, null> : never
    

    It is similar to the DbResult definition:

    export type DbResult<T> = T extends PromiseLike<infer U> ? U : never
    

    Except that generic type T is referencing the data part of the query Result object. Long story short though, it must also be typeof query like DbResult because T must extend PromiseLike<>.

    This is part of a larger concept in TS called Conditional Types, and TS documentation about this can be found here: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html