Created
February 11, 2025 10:04
-
-
Save stefan-girlich/aa2ee43bfdbac8b25dbc2474ccf74d88 to your computer and use it in GitHub Desktop.
Workaround for faulty Supabase query data types, i.e. when using computed relationships
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Fixes a single Supabase query response by replacing a specific field with a given type. | |
* Useful for overriding false-negative errors in Supabase response types for computed relationships. | |
* | |
* @see https://github.com/supabase/supabase-js/issues/1364 | |
* @template T - the original type to modify, or null | |
* @template K - key of the field to replace in T | |
* @template R - type to replace the field with | |
* | |
* @example | |
* type RawType = { | |
* id: number; | |
* name: string; | |
* organization: SelectQueryError<"could not find the relation ..."> | |
* }; | |
* | |
* type FixedType = FixSupabaseDataSingle< | |
* RawType, | |
* 'organization', | |
* { id: number; name: string; } | |
* >; | |
* // Result: { | |
* // id: number; | |
* // name: string; | |
* // organization: { id: number; name: string; } | |
* // } | |
*/ | |
export type FixSupabaseDataSingle< | |
T extends any | null, | |
K extends keyof NonNullable<T>, | |
R extends Record<any, any> | null, | |
> = Omit<NonNullable<T>, K> & { | |
[P in K]: R | |
} | |
/** | |
* Fixes an array of Supabase query responses by replacing a specific field in each item with a given type. | |
* Useful for overriding false-negative errors in Supabase response types for computed relationships. | |
* | |
* @see https://github.com/supabase/supabase-js/issues/1364 | |
* @template T - the original array type to modify, or null | |
* @template K - key of the field to replace in each array item | |
* @template R - type to replace the field with in each array item | |
* | |
* @example | |
* type RawType = Array<{ | |
* id: number; | |
* name: string; | |
* organization: SelectQueryError<"could not find the relation ..."> | |
* }>; | |
* | |
* type FixedType = FixSupabaseDataArray< | |
* RawType, | |
* 'organization', | |
* { id: number; name: string; } | |
* >; | |
* // Result: Array<{ | |
* // id: number; | |
* // name: string; | |
* // organization: { id: number; name: string; } | |
* // }> | |
*/ | |
export type FixSupabaseDataArray< | |
T extends any[] | null, | |
K extends keyof NonNullable<T>[number], | |
R extends Record<any, any> | null, | |
> = Array< | |
Omit<NonNullable<T>[number], K> & { | |
[P in K]: R | |
} | |
> | |
/** | |
* Replaces a type nested in an given type according to a given path. | |
* Useful for overriding false-negative errors in Supabase response types for computed relationships. | |
* | |
* @see https://github.com/supabase/supabase-js/issues/1364 | |
* @template T - the original type to modify, or null | |
* @template P - path of properties to replace, starting at the root-level of T and descending one level per item | |
* @template R - type to replace the type at the lowest (last) keys in P | |
* | |
* @example | |
* type RawSupabaseType = { | |
* organizations: Array<{ | |
* id: number; | |
* name: string; | |
* parent_organization: SelectQueryError<"could not find the relation between ..."> | |
* }> | |
* }; | |
* | |
* type FixedSupabaseType = SupabaseDeepReplace< | |
* RawSupabaseType, | |
* ['organizations', 'parent_organization'], | |
* { id: number; name: string; }>; | |
* // Result: { | |
* // organizations: Array<{ | |
* // id: number; | |
* // name: string; | |
* // parent_organization: { id: number; name: string; } | |
* // }> | |
* // } | |
*/ | |
export type FixSupabaseDataDeep< | |
T extends any | null, | |
P extends [keyof NonNullable<T>, ...string[]], | |
R extends Record<string, any> | null, | |
> = P extends [infer First, ...infer Rest] | |
? First extends keyof NonNullable<T> | |
? { | |
[K in keyof NonNullable<T>]: K extends First | |
? NonNullable<T>[First] extends (infer A)[] | |
? Array< | |
Rest['length'] extends 0 | |
? R | |
: FixSupabaseDataDeep< | |
A, | |
Rest extends [keyof NonNullable<A>, ...string[]] ? Rest : never, | |
R | |
> | |
> | |
: Rest['length'] extends 0 | |
? R | |
: FixSupabaseDataDeep< | |
NonNullable<T>[First], | |
Rest extends [keyof NonNullable<NonNullable<T>[First]>, ...string[]] | |
? Rest | |
: never, | |
R | |
> | |
: NonNullable<T>[K] | |
} | |
: never | |
: { | |
[K in keyof NonNullable<T>]: K extends keyof NonNullable<R> | |
? NonNullable<R>[K] | |
: NonNullable<T>[K] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment