文字列バリデーションにtrim()を忘れずに
2026-03-01
3 days ago
開発環境
- zod 4.3.6
- next 16.1.6
- react 19.2.4
前提
フォームのバリデーションで Zod を利用していると、次のようなコードを書くことが多いと思います。
const schema = z.object({
name: z.string().min(1, "必須項目です"),
})一見これで問題なさそうに見えます。しかし、この定義にはある落とし穴があります。
それは「空白文字のみの入力」を許容してしまうことです。
例えば、ユーザーが " "(半角スペース1つ)を入力した場合でも、文字列の長さは1なので min(1) を通過してしまいます。
本題
空白だけの入力は「実質未入力」
1行のテキスト入力(名前、タイトル、件名など)では、
- 未入力
- 空白だけ入力
は、どちらも「未入力」として扱いたいケースがほとんどです。
しかし z.string().min(1) だけでは、空白のみの文字列を弾くことができません。
解決策:trim() を忘れない
そこで重要なのが trim() です。
const schema = z.object({
name: z.string().trim().min(1, "必須項目です"),
})trim() を入れることで、
- " " → ""
- " " → ""
- " 山田 " → "山田"
のように、前後の空白が除去されます。
そのうえで min(1) が評価されるため、空白のみの入力はエラーになります。
1行テキスト入力ではほぼ必須
特に以下のような項目では、trim() はほぼ必須と言ってもよいです。
- ユーザー名
- タイトル
- 件名
- タグ名
- 検索キーワード
なぜ trim() を付け忘れがちなのか
- min(1) だけで「必須チェックをしている気になる」
- UI上は空白が目立たないため見落としやすい
- コピペでスキーマを書き回している
その結果、「空白だけで登録できてしまう」バグが本番で発覚することがあります。
特に管理画面や社内ツールでは見逃されがちなので注意が必要です。
さいごに
1行テキスト入力のバリデーションでは、
z.string().trim().min(1)を基本形として覚えておくと安全です。
「min(1)を書いたからOK」ではなく、
- 空白だけは許可していないか?
- 前後のスペースは除去しているか?
まで考えると、より堅牢なフォームになります。
小さな差ですが、プロダクト品質に直結するポイントです。