logo

文字列バリデーションに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」ではなく、

  • 空白だけは許可していないか?
  • 前後のスペースは除去しているか?

まで考えると、より堅牢なフォームになります。

小さな差ですが、プロダクト品質に直結するポイントです。

参照