🔱

Docker + Prisma + React でTodoアプリを作ってみた!

に公開

👋 はじめに

こんにちは!
最近、社内で 「今後の新規開発はTypeScriptを積極的に使っていこう!」 という流れが本格化してきました。

しかし、これまで自分はTypeScriptを業務でしっかり触った経験がありませんでした。「JavaScriptに型がついたものでしょ?」くらいのぼんやりとした知識しかありませんでした。

そこで、まずはTypeScriptに慣れるための第一歩として、定番の「Todoアプリ」開発に挑戦してみることにしました。どうせ作るなら、それっぽく実践的な構成にしたいと思い、以下の技術スタックを選びました。

  • 環境構築: Docker / PostgreSQL
  • バックエンド (API): TypeScript / Node.js (Express) / Prisma
  • フロントエンド (UI): React / TypeScript

この記事では、TypeScript未経験だった自分が、実際にTodoアプリをフルスタック(バックエンドとフロントエンドの両方)で作ってみて感じた、率直な 「型の恩恵」「開発体験(DX)」 について、感想を中心にまとめていきます。


1. 🐳 データベースの起動 (Docker)

まずはデータの入れ物であるPostgreSQLをDockerで起動します。

docker-compose.yml を書くだけで、コマンド一つ(docker compose up -d)で自分のPCを汚さずにデータベース環境が立ち上がるのは、やはり非常に快適でした。開発の「よーいドン」がとてもスムーズです。


2. 🤖 バックエンドAPI実装 (TypeScript + Prisma)

ここからが本題のバックエンド開発です。TypeScriptとPrismaの組み合わせが、想像以上に強力でした。

Prismaスキーマと「自動生成される型」

Prismaはschema.prisma というファイルにDBモデルを定義します。

prisma/schema.prisma
// prisma/schema.prisma (抜粋)
model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  completed Boolean  @default(false)
  createdAt DateTime @default(now())
}

npx prisma migrate dev を実行すると、DBにテーブルが作られると同時に、このモデルに対応するTypeScriptの型が自動生成されます。

DBのスキーマ定義(schema.prisma)が、そのままTypeScriptの型定義(Todo型など)に なります。 Goで使っていたSQLBoilerを思い出しました。

「型」がAPI実装をガイドしてくれる

ExpressでAPIサーバー(src/index.ts)を実装していきます。 SQLBoilerが「型安全なSQLビルダー/クエリ実行」だとしたら、Prismaは 「TypeScriptコードとDB操作がよりシームレスに融合している」 的な感覚です。

// src/index.ts (雰囲気の抜粋)
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient(); // この時点でDB接続の準備OK
const app = express();

// [POST] /todos : 新しいTodoを作成
app.post('/todos', async (req, res) => {
  // req.body の中身が何か、コードを追わなくても型からわかる
  const { title } = req.body;

  // prisma.todo.create の引数 (data) にも型がついている!
  const todo = await prisma.todo.create({
    data: {
      title: title,
      // completed: ... や createdAt: ... を書き忘れても、
      // schema.prisma の @default が効くのがわかる
    },
  });

  // レスポンス (todo) も、Prismaが生成した Todo 型だとわかる
  res.json(todo);
});

findManycreate といったメソッドAPIが、よりJavaScriptのオブジェクト操作やメソッドチェーンに近い感覚で設計されています。エディタの補完も強力で、prisma.todo. と打つとメソッドが補完されるだけでなく、その引数オブジェクト(data:where:orderBy: など)の中身まで完全に型が効きます。

Go+SQLBoilerが「型安全にSQLを組み立てる」体験だとすれば、TypeScript+Prismaは 「型安全なJSオブジェクトを操作しているだけで、裏側でSQLが実行されている」 という、一段抽象化された体験でした。これはTypeScriptという言語の特性と非常にマッチしていると感じます。


3. 🎨 フロントエンドUI実装 (React + TypeScript)

次にReactでフロントエンドを作ります。バックエンドと同じくTypeScriptを採用しました。

フロントエンドのことは正直あまり詳しくなかったので、ここはAI(ChatGPTやGeminiなど)とペアプログラミングしながら進めました。

面白かったのは、AIが生成したコードに対しても、TypeScriptの型チェックが強力なレビューアとして機能したことです。
例えば、APIから取得するデータ(Todo[])の型を先に定義しておくと、AIが雑に any 型を使おうとしたり、存在しないプロパティ(todo.name など)にアクセスしようとしたりした瞬間に、エディタが「型が違う!」とエラーを出してくれます。

AIに実装を任せつつも、人間は「型」という設計図をレビューすることで、品質を担保できる感覚がありました。

TypeScriptフルスタックの真価(今回は試せなかったこと)

AIとペアプロする中で、TypeScriptでフルスタック開発を行う最大のメリットは、やはり**「型の共有」**にあるのだと痛感しました。(今回は別々のプロジェクトとして作成したため、この恩恵は試せませんでしたが…)

もし「モノレポ」(一つのリポジトリで管理する構成)などを採用していれば、以下のような大きな恩恵があるはずです。

  • 型の共有: バックエンドのPrismaが生成した Todo 型を、フロントエンドでもそのままインポートして利用できます。これにより、APIのレスポンスとフロントが期待するデータ構造の間に「ズレ」がなくなることが保証されます。
  • API仕様の変更に強い: APIの仕様変更(例: Todopriority を追加)があった場合、共有された型定義を更新するだけで、フロント・バック両方でコンパイルエラーが検知できるため、修正漏れを防げます。
  • 開発体験の一貫性: 同じ言語、同じ構文で開発できるため、フロントエンドとバックエンドを行き来する際の「脳のスイッチングコスト」が大幅に下がるようです。

🎉 まとめ: AIとペアプロして感じた『型』の価値

TypeScript未経験からでしたが、AIとも協力しつつ、一連の開発の流れを掴むことができました。

  1. PrismaとTypeScriptの「直感的な」連携: Go+SQLBoilerで「スキーマからのコード生成」は経験済みでしたが、Prismaの体験は新鮮でした。まるでJSの配列を filter するかのような直感的なAPIでDBを操作できる点は、SQLBoilerとはまた違った快適さがありました。

  2. AI時代の「型」の重要性: フロント開発はAIとペアプロで進めましたが、そこで感じたのは「型の共有」の重要性です。モノレポで型を共有すれば、API仕様のズレをコンパイル時に検知できる安心感は、Go言語でバックエンドを書いていた時にはなかった大きな魅力です。

  3. 型は「AIのレビューア」になる: TypeScript自体の基本的な恩恵(エディタ補完)も強力ですが、それ以上に「AIが生成したコードの品質を担保する仕組み」として型が機能することを実感できました。

小さなTodoアプリでtypescriptでの開発の流れは体験できたかと思います!あざした!


💻 成果物

https://github.com/kmkm92/typescript-todo-app


📕 参考

https://zenn.dev/hikar4215/articles/69e23611452e27
https://zenn.dev/sprout2000/articles/40328708afaeb9
https://qiita.com/01psa/items/d8daf57174cec8b74800

株式会社アクティブコア

Discussion