logo

両面TypeScriptのとき型をどう共有する?

2026-04-08
10 days ago

開発環境

  • TypeScript 5.4
  • orval 7.x
  • REST API(GraphQL・モノレポは対象外)

前提

フロントエンドとバックエンドが別リポジトリで、両方 TypeScript を使っているケース。

よくある問題として、API のレスポンス型を両側で二重管理してしまう。

// バックエンド
type User = { id: number; name: string; email: string }

// フロントエンド(コピペして手動で揃える)
type User = { id: number; name: string; email: string }

どちらかが変更されたとき、もう片方を忘れるとバグになる。

本題

選択肢の全体像

大きく2つのアプローチがある。

  • 手動で共有(コピペ・型定義ファイルを手渡し):最もシンプルだが、ズレが起きやすい
  • OpenAPI スキーマから型を生成:スキーマを単一の正にする

この記事では OpenAPI スキーマから型を生成するアプローチ を整理する。

OpenAPI / Swagger ベースの型共有

「OpenAPI スキーマを Single Source of Truth にする」という考え方。

全体の流れ

バックエンド → openapi.yaml → (自動生成) → 型 + API クライアント(フロントエンド)
  1. バックエンドが OpenAPI スキーマ(YAML/JSON)を生成・公開する
  2. フロントエンドはそのスキーマから型と API クライアントを自動生成する

バックエンド側:スキーマの作り方

大きく2方向ある。

コードファースト(実装 → スキーマ自動生成)

  • Express + swagger-jsdoc
  • NestJS(デコレータから生成)
  • Hono + @hono/zod-openapi

スキーマファースト(スキーマ → コード生成)

  • openapi.yaml を先に書いてバリデーションやルーティングを生成

実装とスキーマが乖離しにくいという点で、コードファーストが選ばれやすい。

フロントエンド側:orval で型・クライアントを生成

orval は OpenAPI スキーマから TypeScript の型と API クライアントを自動生成するツール。

設定ファイル(orval.config.ts)を用意したうえで、以下のコマンドだけで生成できる。

npx orval

生成されるものの例:

// 自動生成された型
export type User = {
  id: number
  name: string
  email: string
}

// 自動生成された API クライアント
export const getUser = (id: number): Promise<User> =>
  fetch(`/users/${id}`).then((res) => res.json())

👉 スキーマが更新されたらコマンドを叩くだけで型が追従する。型のズレをコンパイルエラーで検知できるようになる。

設定ファイルの例:

// orval.config.ts
import { defineConfig } from 'orval'

export default defineConfig({
  api: {
    input: './openapi.yaml',
    output: {
      target: './src/api/generated.ts',
      client: 'fetch', // fetch / axios / react-query など選べる
    },
  },
})

注意点:スキーマとコードの乖離

⚠️ コードファーストの場合、スキーマ再生成を忘れるとフロントエンドの型が古くなる。

実装を変更 → スキーマ再生成を忘れる → フロントエンドの型が古いまま

🛠 CI でスキーマ生成 + コミットを強制するのが現実解。差分があればコケるようにしておくと安心。

さいごに

以前は「バックエンドが型を変えたのにフロントエンドに伝え忘れた」という事故を何度か経験しました。ドキュメントやチャットで伝えるしかなく、抜け漏れが防げなかった。

OpenAPI + orval に切り替えてからは、スキーマが変わると npx orval を叩いた瞬間に型エラーが出る。「ツールに検知させる」構造に変えるだけで、認識ズレをゼロにできました。

まずはスキーマを出力するところから始めてみるのがおすすめです。

参照