フォームデータ整形とは何か
フォームデータ整形は「UIから入力された生の値(文字列中心・未入力混在・チェックボックスの揺れなど)を、バックエンドが扱いやすい“型の揃ったオブジェクト”に変換する」作業です。ここが重要です:文字列を適切な型(数値・真偽値・日付・配列)に変換し、必須・任意・既定値を明確化し、余計な空白や表記ゆれを正規化する。送信前に“バリデーション→整形→ペイロード作成”の順で処理します。
よくある入力の課題と正規化(トリム・大小・全角半角)
文字列の前処理(必須のベース整形)
const normalizeText = s =>
s == null ? "" : s.trim();
const normalizeLower = s =>
normalizeText(s).toLowerCase();
const normalizeFullToHalf = s =>
normalizeText(s).replace(/[!-~]/g, ch => String.fromCharCode(ch.charCodeAt(0) - 0xFEE0));
JavaScriptここが重要です:前後空白の除去(trim)は基本。検索語やコード類は小文字化で揺れを減らし、ユーザー入力でありがちな全角英数字は半角に揃える。正規化は“関数に閉じる”と再利用が効きます。
数値の安全変換と欠損の扱い
const toInt = (s, def = null) => {
const n = Number.parseInt(normalizeFullToHalf(s), 10);
return Number.isFinite(n) ? n : def;
};
const toFloat = (s, def = null) => {
const n = Number.parseFloat(normalizeFullToHalf(s));
return Number.isFinite(n) ? n : def;
};
JavaScriptここが重要です:空文字は数値にできません。失敗時の既定値(def)を設計し、必要ならエラーにせず“nullで送る”か“バリデーションで弾く”かを決める。
真偽値・チェックボックスの変換
const toBool = v =>
v === true || v === "true" || v === "on" || v === "1";
JavaScriptここが重要です:HTMLフォームはチェック時に “on” や “true” などで来ることがある。仕様上の表現を網羅して真偽値に統一する。
型を揃えたオブジェクトへマッピング(フィールドごとの変換)
生入力からペイロードを作る基本パターン
function toPayload(input) {
return {
name: normalizeText(input.name),
email: normalizeText(input.email).toLowerCase(),
age: toInt(input.age), // 失敗時は null(送信先で判断)
price: toFloat(input.price, 0), // 失敗時は 0 にする仕様
active: toBool(input.active),
tags: toTagsArray(input.tags), // カンマ区切り→配列へ
birthday: toIsoDate(input.birthday), // "YYYY-MM-DD"へ揃える
note: normalizeText(input.note) || null // 空なら null に
};
}
function toTagsArray(s) {
return normalizeText(s)
.split(",")
.map(x => normalizeText(x))
.filter(x => x.length > 0);
}
function toIsoDate(s) {
const t = normalizeText(s);
const d = new Date(t);
return Number.isNaN(d.getTime()) ? null : d.toISOString().slice(0, 10);
}
JavaScriptここが重要です:フィールドごとに“入力→変換→既定値”を定義する。空文字のまま送るより、nullで「未入力」を表現するほうがサーバー側で扱いやすい場面が多い。
配列・オブジェクトのフォーム(チェック群・住所・電話)
チェックボックス群→配列(複数選択)
// UI: [{value:"a", checked:true}, {value:"b", checked:false}, ...]
const toSelectedValues = options =>
options.filter(o => toBool(o.checked)).map(o => String(o.value));
JavaScriptここが重要です:入力が混在するため、チェック判定は toBool に集約する。値は文字列へ正規化しておくと辞書化しやすい。
住所のネスト整形(空を除外/必須チェック)
function toAddress(input) {
const addr = {
zip: normalizeFullToHalf(input.zip),
prefecture: normalizeText(input.prefecture),
city: normalizeText(input.city),
line1: normalizeText(input.line1),
line2: normalizeText(input.line2) || null
};
// 必須チェック(例)
if (!addr.zip || !addr.prefecture || !addr.city || !addr.line1) {
return { error: "address_required", value: addr };
}
return { value: addr };
}
JavaScriptここが重要です:ネストは“部分オブジェクト”を作った後に必須検証。失敗時はエラーコード+部分値を返して再入力支援に使う。
電話番号の正規化(数字だけ・国番号)
function toPhone(s, country = "JP") {
const digits = normalizeFullToHalf(s).replace(/\D/g, "");
if (!digits) return null;
if (country === "JP" && digits.length === 10) return `0${digits.slice(1)}`;
return digits; // 最低限“数字のみ”に
}
JavaScriptここが重要です:用途次第でフォーマットは変わるが、まずは“数字だけ”に。国別の細かなルールは段階的に拡張する。
ラジオ・セレクトの既定値と不正値(安全なスキーマ)
許可値リストでガードする
const allowedStatus = new Set(["active", "inactive", "pending"]);
const toStatus = s => allowedStatus.has(s) ? s : "pending";
JavaScriptここが重要です:セレクト値はクライアント側でも“許可値”でガードし、不正値が来たら既定へフォールバック。サーバー側でも同様に検証する二重防御が安全。
バリデーション→整形→エラーの返し方(UXに効く)
段階を分ける(読みやすくテストしやすい)
function validate(input) {
const errors = {};
if (!normalizeText(input.name)) errors.name = "required";
if (!/^\S+@\S+\.\S+$/.test(normalizeText(input.email))) errors.email = "invalid";
const age = toInt(input.age);
if (age == null || age < 0) errors.age = "invalid";
return { ok: Object.keys(errors).length === 0, errors };
}
function shape(input) {
return toPayload(input);
}
function processForm(input) {
const v = validate(input);
if (!v.ok) return { ok: false, errors: v.errors };
return { ok: true, payload: shape(input) };
}
JavaScriptここが重要です:検証(validate)と整形(shape)を分離すると見通しが良く、単体テストが簡単になる。エラーはフィールド単位のコードで返し、UIでメッセージに変換する。
実務の細部(空文字の扱い・null/undefined・既定値)
空文字は“未入力”として null に寄せる
const emptyToNull = s => {
const t = normalizeText(s);
return t.length ? t : null;
};
JavaScriptここが重要です:空文字のまま送るとサーバー側の“必須/未入力”判定が難しくなる。未入力を null に統一すると整合が取れる。
nullish coalescing(??)で既定値を一貫適用
function toPayloadSafe(input) {
return {
perPage: toInt(input.perPage) ?? 20,
active: toBool(input.active ?? false),
q: normalizeText(input.q) ?? ""
};
}
JavaScriptここが重要です:?? は null/undefined のみ既定値に置換。0・空文字・falseを尊重したい場面で安全。
ファイル・FormData の取り扱い(アップロード)
FormData からの抽出と型整形
function fromFormData(fd) {
return {
name: normalizeText(fd.get("name")),
age: toInt(fd.get("age")),
avatar: fd.get("avatar") // File or null
};
}
JavaScriptここが重要です:FormData#get は文字列や File を返す。大文字小文字・空白・数値変換はここでも適用。ファイルはそのまま送る(別途サイズや拡張子の検証が必要)。
送信前の最終整形(余計なフィールドを削る・キー順)
送信用にフィールドを限定する
function toApiPayload(p) {
const { name, email, age, price, active, tags, birthday, note } = p;
return { name, email, age, price, active, tags, birthday, note };
}
JavaScriptここが重要です:内部状態にあるUI専用のフラグや計算値を混ぜない。APIに必要なキーだけに絞って送ると、互いの契約が明確になる。
すぐ使えるレシピ(現場の定番)
一括正規化+整形のパイプ
const normalize = {
text: normalizeText,
lower: normalizeLower,
half: normalizeFullToHalf,
int: toInt,
float: toFloat,
bool: toBool
};
function shapeUserForm(f) {
return {
name: normalize.text(f.name),
email: normalize.lower(f.email),
age: normalize.int(f.age),
subscribed: normalize.bool(f.subscribed),
tags: toTagsArray(f.tags),
birthday: toIsoDate(f.birthday),
note: emptyToNull(f.note)
};
}
JavaScriptエラー付き結果(成功ならペイロード/失敗なら理由)
function submitUserForm(raw) {
const { ok, errors } = validate(raw);
if (!ok) return { ok: false, errors };
const payload = shapeUserForm(raw);
return { ok: true, payload: toApiPayload(payload) };
}
JavaScriptまとめ
フォームデータ整形の核心は「入力の揺れを正規化し、型を明確化し、未入力は null・不正はエラーへ分離する」ことです。文字列は trim・小文字化・全角→半角、数値は安全変換、チェック類は toBool、配列は分割→フィルタで整える。検証(validate)と整形(shape)を別関数にし、送信前に余計なフィールドを落としてペイロードを作る。これを徹底すれば、初心者でも堅牢で読みやすく、実務で信頼できるフォーム処理が書けます。
