メインコンテンツまでスキップ

第277章:データ型ごとのバリデーション(String/Number/Date)🔢

今日は 「文字・数字・日付」それぞれのチェックの書き方を、Valibotでスッキリまとめるよ〜☺️🧡 ポイントはこれ👇

  • 入力はだいたい stringで来る(フォーム・URLなど)😵‍💫
  • Valibotの pipe() で **「チェック → 変換 → 追加チェック」**って順番に積める✨
  • toNumber() / toDate()型変換してから、範囲チェックすると強い💪✨ (valibot.dev)

図解:だいたいこの流れで勝てる💡✨

Validation Pipeline

safeParse()成功なら output、失敗なら issues が取れるよ〜! (valibot.dev)


1) String(文字)のバリデーション 🧵✨

文字はまずこれが鉄板だよ👇

  • trim()(前後の空白消す)
  • nonEmpty()(空文字禁止)
  • minLength() / maxLength()(文字数) (valibot.dev)
  • email()(メール形式)など ✉️ (valibot.dev)

例:ユーザー名(英数字と _ だけ)+メールアドレス

// lib/validators.ts
import * as v from 'valibot';

export const UserNameSchema = v.pipe(
v.string('文字で入力してね🙂'),
v.trim(),
v.nonEmpty('ユーザー名は必須だよ🥺'),
v.minLength(2, '2文字以上にしてね🙏'),
v.maxLength(20, '20文字までだよ〜😌'),
v.regex(/^[a-zA-Z0-9_]+$/, '英数字と _ だけ使えるよ✨')
);

export const EmailSchema = v.pipe(
v.string('文字で入力してね🙂'),
v.trim(),
v.nonEmpty('メールは必須だよ🥺'),
v.email('メールの形がちょっと違うかも✉️'),
v.maxLength(100, 'メール長すぎ!100文字までね🙂')
);

2) Number(数字)のバリデーション 🔢✨

✅ 重要:フォームやURLの数字って「文字」できがち 😭

だからこうするのがめちゃ多い👇

  • まず v.string()
  • toNumber()数値に変換 (valibot.dev)
  • integer() で整数縛り(ページ番号とか) (valibot.dev)
  • minValue() / maxValue() で範囲チェック (valibot.dev)

例:ページ番号(1〜100)

// lib/validators.ts
import * as v from 'valibot';

export const PageSchema = v.pipe(
v.string('ページは文字で来る想定🙂'),
v.toNumber('ページは数字にしてね🔢'), // 変換できないとここでNG
v.integer('小数はダメだよ〜🙂'),
v.minValue(1, '1以上にしてね🙏'),
v.maxValue(100, '100までにしてね🙏')
);

おまけ:小数の文字チェック("12.34"みたいな)🧁

「数に変換する前に、文字として形式だけチェックしたい」なら decimal() が便利だよ〜! decimal は小数や負数OK、digits は0-9だけOK、って違いがあるよ📝 (valibot.dev)


3) Date(日付)のバリデーション 📅✨

日付もだいたい string で来るので、よくある勝ちパターン👇

例:イベント日付(今日以降)

// lib/validators.ts
import * as v from 'valibot';

const startOfToday = () => {
const d = new Date();
d.setHours(0, 0, 0, 0);
return d;
};

export const EventDateSchema = v.pipe(
v.string('日付は文字で来る想定🙂'),
v.isoDate('YYYY-MM-DD で入力してね📅'), // 形式チェック
v.toDate('日付に変換できなかったよ🥺'), // Dateへ変換
v.minValue(startOfToday(), '今日以降にしてね🙏')
);

⚠️ ちょい注意:isoDate() は「形式チェック用の正規表現」なので、例として "2023-06-31" みたいな“存在しない日付”を弾けない場合があるよ(形式は合ってるから)😵‍💫 (valibot.dev) なので toDate() まで通して安全側に倒すのがおすすめ〜!✨ (valibot.dev)


ミニ実践:3つの型をまとめて「イベント登録」の入力チェック🎪✨

// lib/eventSchema.ts
import * as v from 'valibot';
import { EmailSchema, UserNameSchema, EventDateSchema } from './validators';

export const TicketCountSchema = v.pipe(
v.string(),
v.toNumber('枚数は数字でお願い🙏'),
v.integer('枚数は整数だよ🙂'),
v.minValue(1, '1枚以上ね🎫'),
v.maxValue(10, '10枚までだよ🎫')
);

export const EventRegisterSchema = v.object({
userName: UserNameSchema,
email: EmailSchema,
eventDate: EventDateSchema,
ticketCount: TicketCountSchema,
});

Next.jsでサクッと動作確認(Server ComponentでOK)🧪✨

// app/valibot-lab/page.tsx
import * as v from 'valibot';
import { EventRegisterSchema } from '@/lib/eventSchema';

export default function ValibotLabPage() {
const input = {
userName: ' hana_01 ',
email: 'hana@example.com',
eventDate: '2025-12-31',
ticketCount: '2',
};

const result = v.safeParse(EventRegisterSchema, input);

return (
<main style={{ padding: 24 }}>
<h1>Valibot Lab 🧪✨</h1>
<p>success: {String(result.success)}</p>

<h2>result</h2>
<pre>{JSON.stringify(result, null, 2)}</pre>
</main>
);
}

safeParse() はこんな感じで success / output / issues を返してくれるよ〜! (valibot.dev)


小テスト(ゆるめ)📝💖

  1. フォームの ticketCount"2" で来た!まず何にする?🔢
  2. 日付が "2025-12-31" で来た!形式チェック→型変換の順番は?📅
  3. minValue() は String / Number / Date のどれに使える?(全部…?👀) (valibot.dev)

まとめ🎀✨

  • StringtrimnonEmptyminLength/maxLength が鉄板🧵
  • Number:だいたい string → toNumber → integer → min/max 🔢 (valibot.dev)
  • DateisoDate → toDate → min/max が強い📅 (valibot.dev)
  • safeParse で「失敗しても投げない」チェックができる🧪 (valibot.dev)

次の 第278章 では、これを Server Actionsの入力検証にそのまま接続して「フォーム送信=安全」まで持っていくよ〜!🚀🔒