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

第6章:「型で守れること」と「実行時に守ること」分けよう 🧩✅

第6章:「型で守れること」と「実行時に守ること」分けよう 🧩✅

この章はね、超重要な“分岐点”だよ〜!✨ ここを押さえると「不変条件を守る設計」が一気にスムーズになるよ🛡️💎


0. いまの最新状況ちょいメモ 🗞️✨(安心材料)

  • TypeScript の安定版は「5.9.3」タグが最新として公開されてるよ(2025-10-01)📌 (GitHub)
  • TypeScript チームは「6.0 は 5.9 と 7.0 の橋渡し(bridge)」って位置付けを明言してるよ🧩(早めの 2026 を狙う話も) (Microsoft for Developers)
  • VS Code は「TypeScript の言語サービス」と「コンパイラ(tsc)」が別物って公式に説明してるよ(ページ更新 2026-01-08)✍️ (Visual Studio Code)
  • 実行時バリデーションの定番 Zod は v4 系が安定していて、GitHub では v4.3.5 が Latest(2026-01-04)だよ📦✨ (GitHub)

1. この章でできるようになること 🎯✨

  • 「型で守れること / 実行時に守ること」を仕分けできる🧺✅
  • 外から来たデータを “まず unknown 扱い” して安全に中へ入れられる🚪🕵️‍♀️
  • 「境界で実行時チェック → 中は型で固定」の二段構えが作れる🧪🔒

2. まず結論:二段構えモデルが最強 🛡️💎

不変条件を守る基本はこれ👇✨

① 境界(入口)で実行時検証する 🧪 ② ドメイン(中)では型を信じて進む 🔒

イメージはこんな感じ👇

外部入力(信用しない😤)
↓ unknown
境界で検証🧪(parse / validate)
↓ OKなら
ドメイン型💎(信用してOK🙂)

業務ロジック(if地獄が減る✨)

3. TypeScriptの「型」で守れること(コンパイル時)🧠✅

TypeScript が得意なのは “プログラムの書き方” のミス防止 だよ✨

たとえば👇

  • プロパティ名の打ち間違いを防ぐ(user.emial みたいなやつ💥)
  • ユニオンで選択肢を固定できる("Free" | "Pro" みたいに🎫)
  • 分岐を型で安全にできる(タグ付きユニオンの世界🏷️)
  • null/undefined を扱うミスを減らす(ちゃんと意識できる🙂)

でもね…ここがポイント⚠️

TypeScript の型は “実行時には存在しない” (コンパイルすると消える=JavaScriptだけが動く)🫥


4. 型だけでは守れないこと(実行時の現実)😅🌪️

外から来るデータって、だいたいこう👇

  • フォーム入力(文字列だらけ)⌨️
  • APIリクエスト(JSON)📡
  • DBからの復元(壊れた古いデータもありえる)🗄️
  • 外部API(欠損・型違い・単位ズレ)🤯

ここで怖いのは…

「型が付いてる“つもり”」で進むこと 😱 (as で黙らせると、事故が起きた瞬間にドカーン💥)


5. 入口は unknown で受けるのが基本 🕵️‍♀️❓

「外から来た値」は、まず unknown 扱いにするのが王道だよ✨ (any は “何でもOK” になって、守りが崩壊しやすい😵‍💫)

✅ ありがちな事故:JSON.parse

// ⚠️ JSON.parse の戻りは「なんでもあり」になりがち
const raw = JSON.parse('{"id": 123, "email": "a@b.com"}');

// 😱 as で黙らせると、実行時に爆発するかも
type User = { id: string; email: string };
const user = raw as User;

// ここで user.id は「stringのはず」だけど実際は number かも…
console.log(user.id.toUpperCase()); // 💥 123 に toUpperCase はない!

「型がある=安全」じゃない 「検証してから型を与える=安全」 だよ🛡️✨


6. じゃあどうする?入口の武器は3つ 🧰✨

武器A:型ガード関数(軽め)🛡️

「これは UserDTO っぽいよね?」を自分でチェックするやつ🙂

type UserDTO = { id: string; email: string };

function isUserDTO(x: unknown): x is UserDTO {
if (typeof x !== "object" || x === null) return false;

const o = x as Record<string, unknown>;
return typeof o.id === "string" && typeof o.email === "string";
}

function parseUserDTO(x: unknown): UserDTO {
if (!isUserDTO(x)) throw new Error("UserDTOの形じゃないよ🥲");
return x;
}

👍 小規模ならこれでもOK 👀 でも項目が増えると手書きが大変になりがち💦


武器B:asserts(失敗したら止める宣言)🚨

「ここを通ったら型は確定!」って強く言い切るやつ✨

type UserDTO = { id: string; email: string };

function assertUserDTO(x: unknown): asserts x is UserDTO {
if (typeof x !== "object" || x === null) throw new Error("objectじゃない🥲");

const o = x as Record<string, unknown>;
if (typeof o.id !== "string") throw new Error("idがstringじゃない🥲");
if (typeof o.email !== "string") throw new Error("emailがstringじゃない🥲");
}

function parseUserDTO(x: unknown): UserDTO {
assertUserDTO(x);
return x; // ここでは UserDTO として扱える✨
}

武器C:スキーマ(Zod など)📐✅(この教材の“定番ルート”)

スキーマの良いところは👇

  • 検証ルールがまとまる🧱
  • エラーメッセージを組み立てやすい🫶
  • “検証したら型が付く” を体験しやすい✨

Zod v4 は安定してて、最新版は v4.3.5 が Latest だよ📦 (GitHub)

import { z } from "zod";

const UserDTOSchema = z.object({
id: z.string().min(1),
email: z.string().email(),
});

type UserDTO = z.infer<typeof UserDTOSchema>;

export function parseUserDTO(input: unknown): UserDTO {
return UserDTOSchema.parse(input); // 失敗したら例外(後でResult型にもできるよ✨)
}

7. 「どこまでをスキーマで?どこからをドメインで?」線引きルール 🧵✨

ここ、迷いやすいから “ざっくり基準” を置くね🙂

✅ スキーマ(境界)でやること 📐

  • 必須かどうか
  • 型(string/number/boolean)
  • だいたいの範囲(min/max)
  • メール形式、UUID形式…みたいな “一般形” ✉️

✅ ドメイン型(中)でやること 💎

  • ビジネス固有のルール 例:

    • 価格は「税計算後に端数ルールがある」💰
    • 在庫は「引当中は減らせない」📦
    • 会員ランクは「ある条件でしか上がらない」👑

スキーマは “入口の門番” 👮‍♀️ ドメイン型は “城のルール” 🏰 って覚えるとラクだよ〜😊✨


8. VS Codeで起きがちな混乱:言語サービスと tsc は別 🧠💡

VS Code は賢く補完してくれるけど、それは TypeScript の言語サービス の仕事。 一方で コンパイル(tsc) は別で、ワークスペースに入れたバージョンとズレることもあるよ〜🙂

公式も「言語サービスとコンパイラは別」って説明してる📌 (Visual Studio Code)

この教材では、「境界で unknown → 検証」 ができてれば、ツール差分で崩れにくい設計になるよ🛡️✨


9. AI活用コーナー 🤖💖(この章でめちゃ効く!)

コピペで使える質問テンプレ置いとくね👇✨

  • 「この入力仕様から、不変条件を列挙して。型で守れるもの/実行時検証が必要なものに分類して」🧠🧺
  • 「unknown を受け取って UserDTO に変換する関数を書いて。型ガード版と Zod版の両方」🛠️
  • 「Zod スキーマの境界値テスト観点を10個出して」🧪📋
  • 「as を使わずに型安全にする書き方に直して」🚫➡️✅

10. ミニ課題 🎲✨(手を動かすと一発で体に入る!)

課題A:仕分けクイズを自分で作る🧺

あなたの題材(例:会員登録、注文、投稿…)で 不変条件を 10個 書いて、こう分類してみて👇

  • 型で守れる✅
  • 実行時チェックが必要🧪
  • ドメイン固有(VOで守る予定)💎

課題B:境界関数を1本作る🚪

  • 入力:unknown
  • 出力:UserDTO(検証済み)
  • 失敗:エラー(メッセージはやさしめに🫶)

Zod版が作れたら最高だよ〜🎉


11. よくある落とし穴 🕳️😱

  • 「as」で黙らせて、静かに爆弾を運ぶ💣
  • any を入口で使ってしまい、境界の意味が消える🫥
  • 検証後もずっと if チェックし続けてしまう(“中は信じる”ができてない)🌀
  • スキーマに全部詰め込みすぎて、ドメインのルールが迷子になる🧳💦

12. まとめ ✅✨(この章の合言葉)

  • 型は“書き方”を守る🧠
  • 実行時検証は“現実のデータ”を守る🧪
  • 境界で unknown → 検証 → 型付け 🚪🔒
  • 中では型を信じて、if を減らす 🧹✨

次の章からは、この考え方を使って「string/number地獄」をわざと体験して、抜け出す準備をしていくよ〜🧟‍♀️➡️😇✨