0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

訂正記事: Zod の `string.nonempty()` は使わないでください(理由と置換レシピ)

Posted at

訂正記事: Zod の string.nonempty() は使わないでください(理由と置換レシピ)

この記事は、過去に「Zod の nonempty() を推奨」と書いてしまった内容を訂正するものです。string フィールドは nonempty() ではなく min(1)(必要なら trim() 併用)で扱うのが現在の実務的ベストプラクティスです。


結論(先に断定)

  • string に対する .nonempty() は採用しない。
    代わりに z.string().min(1) を使う。空白だけ(' ')も弾きたいなら z.string().trim().min(1)
  • 配列/Set 向けの .nonempty() は引き続き有効z.array(T).nonempty() / z.set(T).nonempty() は使ってよい)。
  • 一部のバージョンでは string.nonempty() が実行できることがあるが、公式の説明・コミュニティ議論は min(1) を推奨しており、事実上の非推奨運用と考えるのが安全。

背景と経緯(要点だけ)

  • もともと「空文字を簡単に弾きたい」という要望から string.nonempty() を求める声がありました(Issue #63)。
  • その後、「z.string() は“型が string か”しか見ない。空文字 '' は string として妥当」という設計が再確認され、
    “必須”は長さ制約(min(1))で書く方針が広く共有されるようになりました。
  • 実務(特に React Hook Form など)では 未入力既定値が '' になるケースが多く、trim().min(1) が最小公倍数として落ち着いています。
  • 以降の議論では、空と最小文字数でメッセージを分ける同じ記述をヘルパー化する空白専用の規約を regex/refine で補うといった具体策に収束しています。

参考:


置換レシピ(非推奨からの移行)

1) もっとも基本:必須(空文字禁止)

const name = z.string().min(1, { message: '必須です' });

2) 空白だけも禁止(' ' を弾く)

const name = z.string().trim().min(1, { message: '必須です' });

trim() は前後の空白を除去します。内部の連続空白まで潰す要件は別途検討。

3) 「空」と「最小文字数未満」で別メッセージを出す

const title = z
  .string()
  .refine((s) => s.trim() !== '', { message: '空です' })
  .refine((s) => s.length >= 3, { message: '3文字以上で入力してください' });

4) 同じパターンを何度も書かない(ヘルパー化)

const requiredStr = (msg = '必須です') =>
  z.string().trim().min(1, { message: msg });

const schema = z.object({
  firstName: requiredStr(),
  apiEndpoint: requiredStr('API_ENDPOINT は必須です'),
});

5) 配列/Set はこれまで通り

const tags = z.array(z.string()).nonempty('1件以上選択してください');

React Hook Form(RHF)との実務ポイント

  • 多くのフォーム実装では 未入力既定値が ''(空文字)
    → スキーマ側で trim().min(1) を入れておくと安定。
  • HTML の required 属性だけでは 空白入力を防げない。
    スキーマで担保する(UI とバリデーションを分離)。

よくある勘違い・落とし穴

  1. required_error を付ければ空文字も弾ける
    弾けませんrequired_error は型エラー用。min(1) が必要です。
  2. ドキュメントに .nonempty() がある=string でも使える
    → その説明は 配列/Set 向けstring は min(1) を使うのが現在の前提。
  3. 空白だけを弾けない
    trim().min(1) を使うか、要件に応じて refine / regex を追加。

最小の差分(before/after)

- const name = z.string().nonempty('必須です');
+ const name = z.string().min(1, { message: '必須です' });

- const name = z.string().nonempty('必須です'); // '   ' を素通りしうる
+ const name = z.string().trim().min(1, { message: '必須です' });

まとめ(訂正の趣旨)

  • string の“必須”は min(1)、空白対策は trim() 併用
  • .nonempty()配列/Set では有効だが、string では使わない
  • このポリシーで統一すると、フォーム実装(特に RHF)での不具合や認知負荷を減らせます。

参考リンク


タイトル候補

  • 訂正記事: Zod の string.nonempty() は非推奨運用です(理由と置換レシピ)
  • Zod string の必須は min(1) 一択.nonempty() を使わない理由
  • 実務ガイド: 空文字/空白を確実に弾く Zod スキーマの書き方
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?