Skip to content

Instantly share code, notes, and snippets.

@stefan-girlich
Created February 11, 2025 10:04
Show Gist options
  • Save stefan-girlich/aa2ee43bfdbac8b25dbc2474ccf74d88 to your computer and use it in GitHub Desktop.
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
/**
* 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