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