Demo, all content is generated
Question

Property 'name' does not exist on type 'never' on every Supabase query

Solved · 301 views · asked by santi_dev_wannabe · edited

Every query in my project has red squiggles:

const { data } = await supabase.from("projects").select("id, name").single();
console.log(data.name);
// Property 'name' does not exist on type 'never'. ts(2339)

It works at runtime. Cursor wrote a types/database.ts by hand at the start, based on my tables, and passes it to createClient<Database>(). When I remove the <Database> part the errors go away but then everything is any.

What I’ve tried

Asked Cursor to fix the types, it added more fields to database.ts and one as any. Restarted TS server.

Comment
Did you write types/database.ts yourself or was it generated? jb_supa · edited

3 answers

Marked as helpful by the asker
jb_supa · edited

The hand-written type doesn't match the shape supabase-js expects (it wants public: { Tables: { x: { Row, Insert, Update, Relationships } }, Views, Functions, Enums, ... }). When one piece is missing, the generics fall through to never.

Don't hand-write it, generate it:

npx supabase gen types typescript --project-id <your-ref> > types/database.ts

(--local instead of --project-id if you run Supabase locally.) Keep createClient<Database>() as is.

Add it as a script so you re-run it after each migration:

"db:types": "supabase gen types typescript --project-id <ref> > types/database.ts"
Comment
Generated file is 400 lines vs Cursor's 60 lol. All red gone. santi_dev_wannabe · edited
Add a line in your cursor rules: 'types/database.ts is generated, never edit it'. Otherwise it will 'fix' it again. jb_supa · edited
mira_dev · edited

And for .single(): data is still possibly null (no row or an error). Check error first, then TS narrows it:

const { data, error } = await supabase.from("projects").select("id, name").eq("id", id).single();
if (error) throw error;
data.name; // typed
Comment
hannah_reyes · edited

If you've run supabase link already, supabase gen types typescript --linked saves you typing the project ref. Same output.

Comment