😺

Supabase で簡単 & 便利に!データベーススキーマから TypeScript 型定義を自動生成する方法

2025/02/11に公開

✅ 前提条件

  • Supabase にてプロジェクトを作成済み
  • ちなみに筆者はnextjsの公式チュートリアルで作成したRSC(react server components)アプリケーションにsuparbaseを導入しました
    • このチュートリアルのchapter6あたりでsuparbaseのデータベース作成ができます
    • テーブル定義はチュートリアル内で作成したものをそのまま使用しております

Supabase CLI を使用して、データベーススキーマから TypeScript の型定義を自動生成する手順を紹介します。

🔥 Supabase とは?

その前にそもそもSupabaseとは何か、簡単に記載します。
Supabase は、オープンソースの Firebase 代替サービスであり、PostgreSQL をベースバックエンドサービスを提供します。以下のような特徴があります。

  • 認証、データベース管理、ストレージ、リアルタイム機能を提供。
  • クライアントサイドから直接 SQL クエリを実行可能。
  • TypeScript との相性が良く、自動型定義生成機能を備えている。
  • 詳細は公式サイトを参照してください 👉 Supabase 公式サイト

🚀 1. Supabase CLI のインストール

まず、最新の Supabase CLI をインストールします(最新バージョンについては公式サイトを参照してください)。

まず、最新の Supabase CLI をインストールします。

npm i supabase@">=1.8.1" --save-dev

🔑 2. Supabase へのログイン

Supabase CLI を使用するために、ログインを行います。

npx supabase login

このコマンドを実行すると、ブラウザが自動的に開き、認証コードが表示されます。そのコードをコピーし、ターミナルに貼り付けることでログインが完了します。

🛠 3. プロジェクトの初期化

次に、Supabase プロジェクトを初期化します。

npx supabase init

このコマンドを実行する際、Docker が起動していないとエラーになります。必ず Docker を立ち上げた状態で実行してください。

(例)筆者はMacを使用しているので、Docker Desktop for mac を使用して起動しました。

📌 4. TypeScript の型定義を生成

以下のコマンドを実行し、データベーススキーマに基づいた TypeScript の型定義を生成します。

npx supabase gen types typescript --project-id "$PROJECT_REF" --schema public > database.types.ts

ここで、$PROJECT_REF には Supabase プロジェクトの ID を指定します。プロジェクト ID は、以下のような URL で XXX に相当する部分です。

https://supabase.com/dashboard/project/XXX

🔍 5. 生成された TypeScript 型定義の確認

コマンドの実行が成功すると、database.types.ts ファイルが作成されます。以下のような型定義が含まれていれば、正常に生成されています。

export type Json =
  | string
  | number
  | boolean
  | null
  | { [key: string]: Json | undefined }
  | Json[];

export type Database = {
  public: {
    Tables: {
      customers: {
        Row: {
          email: string;
          id: string;
          image_url: string;
          name: string;
        };
        Insert: {
          email: string;
          id?: string;
          image_url: string;
          name: string;
        };
        Update: {
          email?: string;
          id?: string;
          image_url?: string;
          name?: string;
        };
        Relationships: [];
      };
      invoices: {
        Row: {
          amount: number;
          customer_id: string;
          date: string;
          id: string;
          status: string;
        };
        Insert: {
          amount: number;
          customer_id: string;
          date: string;
          id?: string;
          status: string;
        };
        Update: {
          amount?: number;
          customer_id?: string;
          date?: string;
          id?: string;
          status?: string;
        };
        Relationships: [
          {
            foreignKeyName: "invoices_customer_id_fkey";
            columns: ["customer_id"];
            isOneToOne: false;
            referencedRelation: "customers";
            referencedColumns: ["id"];
          }
        ];
      };
    };
    Views: {};
    Functions: {};
    Enums: {};
    CompositeTypes: {};
  };
};

このように Row, Insert, Update などの型が適切に生成されていれば、型定義の生成が正しく行われています。

🎯 6. 型定義の使用例

生成された型定義をプロジェクトで活用する方法を紹介します。

database.types.ts のインポート

import { Database } from '@/database.types';

createServerClient で型を適用

createServerClient<Database>()

このようにすることで、Supabase のデータベーススキーマを型安全に利用できます。

import { Database } from '@/database.types';
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export async function createClient() {
  const cookieStore = await cookies()

  return createServerClient<Database>(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          } catch {
            // The `setAll` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  )
}

revenue に自動生成された型が反映されている例

export async function fetchRevenue() {
  try {
    const supabase = await createClient();

    const { data: revenue } = await supabase.from('revenue').select('*');

    return revenue ?? [];
  } catch (error) {
    console.error('Database Error:', error);
    throw new Error('Failed to fetch revenue data.');
  }
}

ちなみにrevenueテーブルのスキーマは下記です。うまくtsの型定義が作成されてますね。

🎉 まとめ

この手順を実行することで、Supabase のデータベーススキーマに基づいた型定義を TypeScript で利用できるようになります。
データベース定義から型が自動生成されるのは便利ですね😊
ぜひ試してみてください!

参考リンク

Next.js チュートリアル - Dashboard アプリ
公式ドキュメント - Generating Types

Discussion