フロントだけ見ていても正しい型定義はできない

フロントだけ見ていても正しい型定義はできない

公開: 2026年01月12日

Tips
要約
  • AIが生成したコードのレビューで型定義を重視し、実態に合わせた厳密な型定義を心がけている。
  • データの入力経路やバリデーションを考慮し、矛盾のない型定義を行うことがプロダクトの品質向上につながる。
  • 型にうるさいことで、将来のバグを未然に防ぎ、信頼性の高いシステムを構築することを目指している。
音声で記事を再生

はじめに

AIがコードを書いてくれる時代になり、「書ける」こと自体の価値はどんどん下がっていると感じています。

私はAIが生成したコードをレビューすることも多いのですが、そのとき必ず見るのが「型定義が正しいかどうか」です。むしろ、ここだけは自分で考えて書くこともあります。

AIに書かせるからこそ、人間が考えるべき「型定義」について整理してみました。

背景

スピード感を持って開発する中で言われるし周りを見ている気づいたことがあります。
私は「だいぶ型定義にうるさいタイプ」だということですw

正直、型をガチガチに決めるのは面倒な時もあります。
なぜ私がそこにこだわるのか実務でのエピソードを交えて書いてみます。

理想と実態のギャップを埋める

一番「嫌だな〜」と思いながら向き合っているのが、入力経路によるデータの汚れです。

  • 現実: 「CSV一括アップロードがあるから、DBの制約は null: true(許可)にせざるを得ない」

  • 理想: 「この機能のフォームからは『必須』でデータが欲しい」

ここで「DBはnull許容だから、フロントの型もなんとなく string | null でいいや」とはしたくないんです。
フォームが必須だからnullの場合ってほんとにあるんかな?どういう時のためにnull: trueになってるんかな?と実装を見てみます。

この機能において、実態はどうあるべきか?を考え、フォームではバリデーションをガチガチにかけ、フロントの型も「ここでは絶対に存在する)」と定義しにいきます。
なのでフロントのバリデーション✖️APIのバリデーション✖️DBの設計を全部見て、GETする時ここは必ずデータあるのか?と判断しています!

DB:    string | null
API:   string         // form経由ではバリデーションあり
API:   string | null  // csvからのbulk import
UI:    string | null  // にせざるをえない

「今あるデータ」に合わせるのではなく、「あるべき姿」にコードを合わせる。
これが、バグを未然に防ぐ一番の近道だと思っています。

「あるはず」という思い込みを捨てる

例えば中間テーブルを扱うとき、つい「紐付いてるはずだからデータはあるやろ」と思いたくなります。
でも、型定義するときには undefined になりえないか確認します。

これもPOSTのエンドポイントで登録するときにバリデーションしてるか見たりします。
中間テーブルだったとしたらカラムにDBレイヤーでのガードはないので、作成されなかったで普通に正常終了したりします。
それでいいのか確認したりすることもありますね。(適当な人もいるので)

POST /products

{
  categoryIds?: string[] // ← そもそも必須でない場合
}

ここで categoryIds 自体が必須でなければ、中間テーブルは作成されないまま正常終了します。
その結果、取得時には undefined になりえます。

// 登録時に必須チェックされている前提
POST /products

{
  categoryIds: string[] // 必須 & length > 0がポイント
}

categoryIds 自体が必須であっても、配列の長さチェックがなければPOST 時に空配列が通ってしまいます。POST時に空配列でも通ってしまうと、中間テーブルは1件も作られません。
GETではinner joinしているので、空配列ではなく「そもそも返ってこない」状態になります。(空配列として返したいなら、left joinが必要)
UI から見れば、これはundefinedと同じです。だから紐付いているはずという前提は置けないなと思います。

厳密に型定義するメリットとしては、初歩的な内容ですが、型に undefined を混ぜると表示側のコンポーネントが「データがない時のハンドリングをしろ!」と怒ってくれます。
そこで初めて、「あ、データがない時は空であることを知らせなきゃ」と気づけます。
配列ならfind使えないよと言ったエラー吐いてくれたりしますね。

型にうるさく確認することで、想定外だったundefinedが混じった時にエラー吐いたりユーザーに「真っ白な画面」を見せない守備力が手に入るんです。

型定義は、CTOとの「対話の入り口」

型をカチッと決めようとすると、必ず「仕様の矛盾」にぶつかります。
そんな時は仕様の確認をします。

「ここ、型を定義しようとしたら矛盾が出るんですけど、データが来なかったら弾くべきですよね?そもそもデータ来ないで登録できていいんですか?」

こんな感じで質問します。既存の実装がバグの温床だったとか普通にあります。
バックエンドのバリデーションに修正が必要だったら修正しつつフロントの型定義したりします。
型について悩むことは、「仕様をデバッグしている」のと同じことだと思います。
コードを書く前にプロダクトの品質を一段上げられた実感が持てる瞬間です。

おわりに

分業していれば、「バックエンドがそう言ったから」と逃げられるかもしれません。 でも、一人で「貫通」して作っているからこそ、DBの制約からフロントでの型安全なUI表示まで、一貫した責任を持ちたいものです。

「型にうるさい」ことは、プロダクトを、そして将来の自分を助けることだと信じています。
不適切な型定義のレビューしているときは私品質守ってるって実感したりしますw

「undefinedもありえるな…嫌だなw」と思うこともありますが、この泥臭い積み重ねが、スピード感を持った開発が求められる環境でも「壊れないシステム」を作る唯一の方法だと思ってます。🍓

シェア!

XThreads
ShiftB Logo
user
吉本茜
山口在住/二児の母/エンジニア
Loading...
記事一覧に戻る
XThreads
0