postgrest-js icon indicating copy to clipboard operation
postgrest-js copied to clipboard

Wrong type for joins with one-to-one relationships

Open probablykasper opened this issue 11 months ago • 10 comments

Bug report

  • [x] I confirm this is a bug with Supabase, not with my own application.
  • [x] I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

I have a profiles and a customers table, with a one-to-one relationship:

profiles: {
  id: text, primary key
  ...
}
customers: {
  id: references profiles.id, primary key
  stripe_customer_id: text, unique
  ...
}

When doing a join between these, TypeScript thinks the type of customers is this:

{
    stripe_customer_id: string;
}[]

But when I run the code, this is the actual type I get:

{
    stripe_customer_id: string;
}

So when accessing the stripe_customer_id property, I get this type error:

Property 'stripe_customer_id' does not exist on type '{ stripe_customer_id: string; }[]'.

To Reproduce

const profile_result = await supabase
	.from('profiles')
	.select('id, customers ( stripe_customer_id )')
	.eq('id', params.id)
	.single()
if (profile_result.data) {
	console.log(profile_result.data.customers.stripe_customer_id)
    //                                        ^
    // Property 'stripe_customer_id' does not exist on
    // type '{ stripe_customer_id: string; }[]'.ts(2339)
}

Expected behavior

The TypeScript type should not be an array for one-to-one relationships. It should match the actual type

System information

  • OS: macOS
  • Version of supabase-js: 2.31.0
  • Version of Node.js: 18.14.2

Additional context

Related:

  • https://github.com/supabase/supabase-js/issues/723

probablykasper avatar Aug 04 '23 23:08 probablykasper

I'm using this as a workaround for now:

export function cast<T>(notAnArray: T[]): T {
  return notAnArray as T;
}

And then:

console.log(cast(profile_result.data.customers).stripe_customer_id)

aslakhellesoy avatar Aug 07 '23 11:08 aslakhellesoy

Update: I've changed my workaround to this:

export function fixOneToOne<T>(objectOrNull: T[]): T | null {
  return (objectOrNull as T) || null;
}

I've changed the return type to T | null because the relationship may indeed be null. In the example above, this would happen when there is no customers record for the given profile.

In the example above, the correct type should be:

{
    stripe_customer_id: string;
} | null

aslakhellesoy avatar Aug 25 '23 11:08 aslakhellesoy

I encountered the same issue today and I found another workaround.

const profile_result = await supabase
	.from('profiles')
	.select('id, customers ( stripe_customer_id )')
	.eq('id', params.id)
	.single()
        .returns<YourType[]>();

# type definition
type YourType {
    the type that you expect without the array
}

FocusCookie avatar Sep 10 '23 11:09 FocusCookie

I am experiencing the exact same issue. As my query is rather nested, workarounds are very inconvenient...

Does anyone know, whether an older version does not have this bug included?

timlgl avatar Sep 12 '23 06:09 timlgl

Seems to still be an issue

orels1 avatar Dec 17 '23 01:12 orels1

Same problem over here, is there a fix for this issue??

albertonii avatar Jan 30 '24 09:01 albertonii

Same problem here.

Silventino avatar Mar 28 '24 12:03 Silventino