Using Conditional Types in Supabase Query results in the TypeScript error, "Type is incompatible with type 'never'."

Query

I have encountered a TypeScript issue while working on a Next.js project with Supabase as the backend. To handle responses from Supabase queries, I created some helper types, but I'm stuck on resolving this problem.

Helper Types Overview:

Below are the helper types I've defined along with their descriptions:

  • DbResult<T>: This type is designed to extract the resolved type from a promise. It determines the type U that the promise resolves to if T is a promise.

  • DbResultOk<T>: This type manages successful query results by inferring the data field from the promise and excluding any null values.

  • DbResultErr: This type is a straightforward alias for PostgrestError, meant to handle errors from Supabase queries.

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

In my function where I execute a Supabase query, I utilize these types:

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

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)
is triggered by the line
const resultOk: DbResultOk<Tables<"FuenteIngreso">[]>> = result.data as Tables<"FuenteIngreso">>[];
. I'm puzzled as to why it defaults to never. Any insights on what might be causing this issue would be greatly appreciated. Also, corrections or clarifications on the helper types concept would be welcomed.

Answer №1

Today, I came across this same issue unexpectedly. It turned out to be related to the return value of a Supabase Postgres Function instead of a table. However, the suggested change should resolve your issue or at least bring you very close to a solution.

Replace this line:

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

with this:

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

Why make this change?

The definition of DbResultOk is as follows:

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

This closely resembles the definition of DbResult:

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

In both definitions, generic type T refers to the data within the query Result object. In short, it is necessary for it to also be typeof query like DbResult because T must extend PromiseLike<>.

This concept falls under Conditional Types in TypeScript, and further information can be found in the TypeScript documentation at: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Simultaneous Activation of Hover Effects on Multiple Elements

I have an array of objects that I'm iterating over. Here is the array: const socialLinks = [ { id: 1, child: ( <> <FaLinkedin className='text-2xl' /> Linkedin </> ), hre ...

What exactly does the context parameter represent in the createEmbeddedView() method in Angular?

I am curious about the role of the context parameter in the createEmbeddedView() method within Angular. The official Angular documentation does not provide clear information on this aspect. For instance, I came across a piece of code where the developer i ...

How to reference an array from one component to another in Angular 2

Within my AddUserComponent, I have a public array declared like this: public arr: Array<any> = [] This array stores the names of users. Now, I need to access these values in another component called AddTopicComponent in order to display the user&a ...

How can you automatically scroll to the top of the window in Next.js after updating the search value in a search bar?

Picture a scenario where there is a button placed somewhere. Once this button is clicked, the text on it moves to my search bar. How can I also make the window scroll down to the search bar after the value is set in the Input element displayed below? ...

Step-by-step guide on redirecting to a different page in NextJS if a dynamic route cannot be found

I need assistance with redirecting users when they access a dynamic route that does not exist. The dynamic route points to a field within a statically defined array of fields. Here is the code snippet for the page: import { fields } from "@/data/fiel ...

Using regular expressions, you can locate and replace the second-to-last instance of a dot character in an email address

I'm looking to replace the second last occurrence of a character in a given string. The length of the strings may vary but the delimiter is always the same. Here are some examples along with my attempted solutions: Input 1: james.sam.uri.stackoverflo ...

Do you notice a discrepancy in the number returned by Javascript's Date.getUTCDate() when the time component is set to

Consider the following code snippet: const d = new Date('2010-10-20'); console.log(d.getUTCDate()); If you run this, the console will output 20. However, if you modify the code like so: const d = new Date('2010-10-20'); d.setHours(0, ...

Dynamic property access using optional chaining in JavaScript

My attempt to utilize optional chaining, a feature provided by TypeScript for safely accessing dynamic properties, seems to be invalid. export const theme = { headers: { h1: { }, h6: { color: '#828286' }, }, } console.in ...

io-ts: Defining mandatory and optional keys within an object using a literal union

I am currently in the process of defining a new codec using io-ts. Once completed, I want the structure to resemble the following: type General = unknown; type SupportedEnv = 'required' | 'optional' type Supported = { required: Gene ...

Having trouble incorporating a title in the header section

I encountered an issue while attempting to include the Fragment, title, and Head. When these are added, an error occurs but when removed, the page displays correctly. I have searched for a solution to this problem but couldn't find anything. import ...

Using TypeScript to call a class method from within another function

Currently, I am working on an Angular 2 application and struggling to grasp the concept of TypeScript's this scope. Within my TypeScript class named SharedService, there is a function called handleError. If this function encounters a 401 status, I wa ...

Webpack is having trouble identifying Node's process module

It has been more than ten years since I last worked with JavaScript, but recently I had an idea for an app that would be best implemented as a NodeJS app. As I delved into the modern JS ecosystem, like many others, I found myself thoroughly confused, haha. ...

Can you explain the significance of <any> when used before a Typescript class constructor parameter?

Currently, I am immersing myself in the Angular - Testing documentation. While going through the section on testing asynchronous services (specifically HTTP services), I came across a class constructor containing an <any> right before the passed argu ...

What is the best way to change the number 123456789 to look like 123***789 using either typescript or

Is there a way to convert this scenario? I am working on a project where the userID needs to be displayed in a specific format. The first 3 characters/numbers and last 3 characters/numbers should be visible, while the middle part should be replaced with ...

Service Worker's fetch event is not triggered upon registering the service worker

Service Worker is a new concept to me. As I delved into learning how to incorporate Service Worker into My Next.js Application, I encountered an issue with the fetch event handler. Oddly enough, the fetch event handler doesn't trigger upon initially r ...

Nest is unable to resolve DataSource in the dependency injection

I've encountered an issue with dependencies while working on my NestJS project. When I try to launch the app, the compiler throws this error at me: [Nest] 16004 - 09.04.2022, 16:14:46 ERROR [ExceptionHandler] Nest can't resolve dependencies of ...

Trouble arises with Service Workers during the transition from Create React App to Next JS

After transitioning our landing page from create-react-app to Next.js, we encountered an issue with users receiving a cached version of the old website. This is due to the default service worker that was registered on their browsers when using create-react ...

transform the string input into a boolean value

Here is my code block: I am trying to obtain the value in boolean format, but the value is always in string format. const handleSubmit = (e) => { e.preventDefault(); if (Object.keys(formData).length == 0) return console.log("Don&apo ...

The Swiper grid functionality is failing to function properly

For the past two days, I've been struggling to successfully implement a Swiper Grid feature in my Next.js application. Despite trying various solutions from stackoverflow and experimenting with different approaches, none of them have resulted in the d ...

What is the best way to include body parameters in a Next.js rewrite?

Consider the following POST request: const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: JSON.stringify({ grant_type: "password&quo ...