Zodの空文字チェック：string.nonemptyが公式Docの記載漏れ?


# Zodで空文字をチェックするなら .nonempty()、もうmin(1) はやめましょう

Zodで入力必須チェックをするとき、`z.string().min(1, '〜')` を使う例をよく見かけます。  
でも、実は `nonempty()` というより直感的なメソッドもあります。

---

## 💡 `nonempty()` はZodの正式なメソッド

例えばこういう定義：

```ts
productCode: z.string().nonempty('商品コードは必須項目です')
```

これは以下と同じ意味です：

```ts
productCode: z.string().min(1, '商品コードは必須項目です')
```

Zodの公式ドキュメント（https://zod.dev/?id=strings）にはなぜか記載されていませんが、**ソースコードを見るとちゃんと存在しています**。

```ts
nonempty(message?: errorUtil.ErrMessage): ZodString;
```

---
入力値のチェックであれば空文字チェックだけで良いので、後で述べるnull,undefinedの考慮は要りません。

## ✅ 最小限のテストケース：空文字のチェック

```ts
it('should fail when productCode is missing', () => {
  const invalidData = { ...baseValidData, productCode: '' }
  const result = productSchema.safeParse(invalidData)
  expect(result.success).toBe(false)
  if (!result.success) {
    expect(result.error.format().productCode?._errors).toContain(
      '商品コードは必須項目です'
    )
  }
})
```

### ✅ テスト結果（`min(1)` / `nonempty` どちらも同じ）

```bash
 PASS  src/app/product/types/__tests__/product-scheme.test.ts
  productSchema - productCode
    ✓ should fail when productCode is missing (24 ms)
```

---

## 🤔 では `undefined` や `null` のときは？

次に `undefined` や `null` を渡してみると…

```ts
it('should fail when productCode is undefined', () => {
  const invalidData = { ...baseValidData, productCode: undefined as any }
  const result = productSchema.safeParse(invalidData)
  expect(result.success).toBe(false)
  if (!result.success) {
    expect(result.error.format().productCode?._errors).toContain(
      '商品コードは必須項目です'
    )
  }
})

it('should fail when productCode is null', () => {
  const invalidData = { ...baseValidData, productCode: null as any }
  const result = productSchema.safeParse(invalidData)
  expect(result.success).toBe(false)
  if (!result.success) {
    const errors = result.error.format().productCode?._errors
    expect(
      errors?.some(e => e.includes('必須')) || errors?.some(e => e.includes('string'))
    ).toBe(true)
  }
})
```

### ❌ テスト失敗（`undefined` のとき）

```bash
 FAIL  src/app/product/types/__tests__/product-scheme.test.ts
  productSchema - productCode
    ✓ should fail when productCode is missing
    ✕ should fail when productCode is undefined
    ✓ should fail when productCode is null

  ● should fail when productCode is undefined

    Expected value: "商品コードは必須項目です"
    Received array: ["Required"]
```

---

## 📌 なぜ `undefined` だけ違うエラー？

Zodでは、`.string()` の型バリデーションが先に走ります。  
キーが存在しない（`undefined`）と「Missing value」とみなされ、**Zodのデフォルトメッセージ `"Required"`** が返ってきます。

一方で `.min(1)` や `.nonempty()` は「**空文字に対する長さチェック**」なので、**そもそも `undefined` には到達しません**。

---

## ✅ 対策：`required_error` を指定する

```ts
productCode: z
  .string({ required_error: '商品コードは必須項目です' })
  .nonempty('商品コードは必須項目です')
```

これで、`undefined` のときも空文字のときも、**同じメッセージで統一**されます。

### 🔁 テスト再実行結果：

```bash
 PASS  src/app/product/types/__tests__/product-scheme.test.ts
  productSchema - productCode
    ✓ should fail when productCode is missing
    ✓ should fail when productCode is undefined
    ✓ should fail when productCode is null
```

---

## ✅ まとめ

| 入力値     | `.min(1)` / `.nonempty()` | 対応策 |
|------------|-----------------------------|--------|
| `''`       | ❌ エラー（OK）            | メッセージ通る |
| `null`     | ❌ 型エラー                | `nullable()`で対応も可 |
| `undefined`| ❌ `"Required"` のまま     | `required_error` で統一しよう |

---

## ✅ おまけ：どちらを使うべき？

- 明示的に「空文字禁止」を書きたいなら `nonempty()` の方が読みやすい
- より一般的なパターンや制約付き（例：`min(5)`, `max(10)`）があるなら `min(x)` の方が柔軟
- チームで統一しておくのがベスト

---

## 🔚 おわりに

Zodの `.nonempty()` は便利なのに知られていない…！  
これを機に `min(1)` だけでなく `nonempty()` の存在も知っておくと、コードがより意図的で読みやすくなります。