Open5
Supabase 開発はじめ memo
typescriptの型の自動生成
Generating TypeScript Typesの通りにやればできる
コード
package.json
"scripts": {
...
"type-gen": "source .env.local && npx supabase gen types --lang=typescript --project-id $SUPABASE_PROJECT_ID --schema public > src/types/database.d.ts"
},
※ .env.localにダッシュボード(Project Settings)で確認できるReference IDを追加する SUPABASE_PROJECT_ID=hogehoge
supabase.ts
import { Database } from "types/database";
...
export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey,
...
yarn type-gen
でsrc/types/database.d.ts
が作られる
スネークケース → キャメルケースの変換
- 参考: Transform snake_case to camelCase
- camelcaseKeysを使って自力で対応する
スネークケースからキャメルケースに変換
import camelcaseKeys from "camelcase-keys";
export type SnakeToCamelCase<S extends string> =
S extends `${infer T}_${infer U}`
? `${Lowercase<T>}${Capitalize<SnakeToCamelCase<U>>}`
: S;
export type SnakeToCamelCaseNested<T> = T extends (infer U)[]
? SnakeToCamelCaseNested<U>[]
: T extends object
? {
[K in keyof T as SnakeToCamelCase<K & string>]: SnakeToCamelCaseNested<
T[K]
>;
}
: T;
export const snakeToCamel = <
T extends Record<string, unknown> | readonly Record<string, unknown>[],
>(
request: T
) => camelcaseKeys(request) as unknown as SnakeToCamelCaseNested<T>;
使い方
取得処理を共通化して変換処理を適応してみる
import { PostgrestError } from "@supabase/supabase-js";
import { useEffect, useState } from "react";
import { snakeToCamel } from "utils/snakeToCamel";
type Fetcher<T> = () => Promise<{
data: T | null;
error: PostgrestError | null;
}>;
export const useFetchFromSupabase = <T>(fetcher: Fetcher<T>) => {
const [data, setDate] = useState<T | null>(null);
const [error, setError] = useState<PostgrestError | null>(null);
useEffect(() => {
const fetchData = async () => {
const { data, error } = await fetcher();
setDate(data);
setError(error);
};
fetchData();
}, [fetcher]);
return { data: data ? snakeToCamel(data) : null, error };
};
実際に使ってみる
import { useFetchFromSupabase } from "hooks/useFetchFromSupabase";
import { supabase } from "libs/supabase";
export const useGetRecipes = () => {
const { data, error } = useFetchFromSupabase(fetcher);
return { data, error };
};
const fetcher = async () => {
const { data, error } = await supabase.from("recipes").select("*");
return { data, error };
};
確認
snake case | camel case | value |
---|---|---|