supabase / supabase-js

An isomorphic Javascript client for Supabase. Query your Supabase database, subscribe to realtime events, upload and download files, browse typescript examples, invoke postgres functions via rpc, invoke supabase edge functions, query pgvector.
https://supabase.com
MIT License
2.86k stars 220 forks source link

Json type: Type instantiation is excessively deep and possibly infinite. #808

Open michaelpumo opened 10 months ago

michaelpumo commented 10 months ago

Bug report

Describe the bug

I have a Vue/Nuxt project with TypeScript which is throwing me an error with the profile table when I try to assign it to a variable based on the types generated from the DB. "Type instantiation is excessively deep and possibly infinite."

The problematic column in question is one called "links" which stores JSONB data. The type that is generated from the Supabase Cli using the command npx supabase gen types typescript creates a self referencing type called Json.

export type Json =
  | string
  | number
  | boolean
  | null
  | { [key: string]: Json | undefined }
  | Json[]

With my (generated) profile row types looking like:

profile: {
  Row: {
    about: string | null
    available: string | null
    avatar: string | null
    avatar_url: string | null
    created_at: string | null
    id: number
    links: Json | null // this is the problematic column.
    location: string | null
    name: string | null
    poster: string | null
    poster_url: string | null
    tagline: string | null
    updated_at: string
    user_id: string
    username: string | null
  }
}

In my Pinia Vue store I get the following error when trying to assign it against these types.

import type { Database } from '@/types/supabase'
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    profile: null as Database['public']['Tables']['profile']['Row'] | null
  }),
  actions: {
    setProfile(profile: Database['public']['Tables']['profile']['Row'] | null) {
      this.profile = profile // Here is where the TS error occurs.
    }
  }
})

I'm guessing this error happens because the generated type is self referencing and TS does not know how deep it would be?

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Create a column and set its type to jsonb
  2. Generate types using the Supabase Cli
  3. Try to do something similar and see that TS complains.

Expected behavior

There should be no TS error.

Screenshots

Screenshot 2023-07-15 at 21 02 12 Screenshot 2023-07-15 at 21 16 15

System information

Additional context

I have not been able to see similar issues with other Supabase users but perhaps the use of JSONB is quite rare?

rahulretnan commented 9 months ago

I'm also facing same issue

soedirgo commented 9 months ago

Hey there, what version of TypeScript are you on? Also, can you put up an example project that demonstrates the issue so I can replicate it?

soedirgo commented 9 months ago

FWIW this seems to run fine: https://www.typescriptlang.org/play?#code/C4TwDgpgBAUgzgewHZQLwCgpQD5TsAJwEskBzTHKJAVwFsAjCAi3ehBAGwgEMkWrqHDvwDeUANoBrCCABceQiVIBdefGSVqSACYQAZiQjaoAX37qk45UA

michaelpumo commented 9 months ago

I did a little more digging and I think it may be an issue in combination with Vue's reactivity and not directly Supabase afterall. You may see something similar with React?

If I try to a assign to a simple variable with let for example it's okay but using ref() in Vue causes the warning, possibly due to Vue / TS not knowing how deep it would have to watch the reactive object.

If I use shallowRef() instead, it's fine: https://vuejs.org/api/reactivity-advanced.html#shallowref

LeOndaz commented 4 months ago

Bump

antoniormrzz commented 3 months ago

The Json type does reference itself. Could it be that? I've also been having the same problem with the Json type columns.

Edit: changed my generated Json type to this and it all went away:

export type Json =
  | string
  | number
  | boolean
  | null
  | { [key: string]: any | undefined }
  | any[]

The error is complaining in my opinion that the line | { [key: string]: Json | undefined } has no end to type instantiation, which when you think about it, is true.

ScreamZ commented 2 months ago

Same issue here does anyone find a good and secure workaround?

I did a little more digging and I think it may be an issue in combination with Vue's reactivity and not directly Supabase afterall. You may see something similar with React?

If I try to a assign to a simple variable with let for example it's okay but using ref() in Vue causes the warning, possibly due to Vue / TS not knowing how deep it would have to watch the reactive object.

If I use shallowRef() instead, it's fine: vuejs.org/api/reactivity-advanced.html#shallowref

Any way to manage this in pinia store without using composition ?

Grovespaz commented 3 weeks ago

Just wanted to confirm this is still an issue at time of writing with the latest version of Vue and supabase-js and makes it impossible to work with supabase-js in any serious capacity when using Typescript and Vue.

shanehoban commented 1 week ago

Fix I'm using is to update your supabase generated types to have Json as below:

export type Json = Record<string, any>
encima commented 1 week ago

Bringing the comments from the related issue made for the CLI here.

Summary of suggestions:

  1. @daniel-j-h suggests to create all Json types as unknown and allow the developer to decide
  2. @shanehoban suggests creating a Json type as Record with a string key and any value
  3. @lauri865 suggests using the MergeDeep from the typefest library
  4. @antoniormrzz suggests changing the Json type to any
  5. @michaelpumo suggests that this could be a combination of Supabase's type generation coupled with Vue's reference handling for watching objects