第2章:まずは敵を知る😇 継承で起きがちな事故あるある💥
この章のゴール🎯✨
この章では、「継承って便利そうなのに、なんで急に地獄になるの?😇」を体感します💥 結論だけ先に言うと…👇
- 継承は “共通化の道具” に見えるけど、実態は “強い結びつき(依存)の契約” になりやすい🪢😵💫
- 「ちょい違い」を増やすと ツリーが爆発🌳💣
- 親の変更が 子に伝染して壊れる🤒(有名な “Fragile Base Class” 問題)📌 (ウィキペディア)
- 機能の組み合わせが必要になると 継承では詰みやすい🧩🧩😇
(ちなみに本日時点だと TypeScript は 5.9 系が “latest” として案内されてます🧁) (TypeScript)
2-1. 事故あるある①:「ちょい違い派生」でツリー爆発🌳💣

「管理者ユーザー欲しいな〜」→「スーパー管理者も」→「閲覧だけ管理者も」→「お試し期間付きも」… ってやっていくと、クラスが 増殖 します😇
まずは地獄の入口サンプル👻
// src/users.ts
export class User {
constructor(public name: string) {}
canRead(): boolean { return true; }
canWrite(): boolean { return false; }
}
export class AdminUser extends User {
canWrite(): boolean { return true; }
}
export class SuperAdminUser extends AdminUser {
canDelete(): boolean { return true; }
}
ここまでは「ふーん?」で済むんだけど…次にこう言われます👇
- 「Admin でも 閲覧専用 がほしい👀」
- 「Admin でも 2段階認証必須 にしたい🔐」
- 「Admin でも お試し期間 がある⏳」
…はい、組み合わせ開始です🧩🧩🧩
継承でやるとこうなる(増殖)😇
- ReadOnlyAdminUser
- TwoFactorAdminUser
- TrialAdminUser
- ReadOnlyTwoFactorAdminUser
- TrialTwoFactorAdminUser
- ReadOnlyTrialTwoFactorAdminUser …って 組み合わせの数だけクラスが必要 になりがち💥
📌ここが学び: 継承は「縦に伸ばす」のは得意だけど、機能を横に組み合わせる のが苦手😵💫
2-2. 事故あるある②:親の変更が子に伝染して壊れる🤒💥(Fragile Base Class)

これが継承のいちばん怖いところの一つ😱 親クラスを「ちょっと改善しただけ」のつもりでも、子が 暗黙に依存してた挙動 が変わって壊れます。 この現象は “Fragile Base Class Problem” としてよく知られてます📌 (ウィキペディア)
ありがちな壊れ方(例)💣
「親がログイン判定の順番を変えた」だけで、子の追加ロジックがズレて事故る…みたいなやつ😇
// src/auth.ts
export class BaseAuth {
protected isLocked = false;
login(password: string): boolean {
if (this.isLocked) return false;
// 親の都合で順序を変えた/内部処理を変えた、とする
const ok = this.checkPassword(password);
if (!ok) this.isLocked = true; // 例:連続失敗でロック
return ok;
}
protected checkPassword(password: string): boolean {
return password === "secret";
}
}
export class PartnerAuth extends BaseAuth {
// 子が「親はロックしない前提」で何かしてた…とかで壊れるパターンが起きがち
protected checkPassword(password: string): boolean {
// 外部連携の都合で例外を投げたり、別の条件にしたり…
if (password === "") throw new Error("empty!");
return super.checkPassword(password);
}
}
📌ここが学び: 継承って「親の中身」を 子が“なんとなく前提にしちゃう” から危ない😇 親の作者は「安全な変更」のつもりでも、子の作者からすると 地雷 になり得る💥
2-3. 事故あるある③:「Aの機能もBの機能も…」で詰む🧩🧩😵💫
継承で「役割」と「機能」を混ぜると、だいたい破綻します💥
たとえば👇
- 役割:User / Admin / Staff
- 機能:ログ追加📝、キャッシュ🧊、リトライ🔁、計測⏱️、権限制御🔐
これを継承で表現しようとすると、設計がこう叫びます:
「それ、無理では?😇」
📌ここが学び: “組み合わせ” が必要な世界は、だいたい 合成の得意分野(後の章で救う🚑🧩)
2-4. 事故あるある④:「is-a」じゃないのに継承しちゃう問題🙅♀️
継承は本来「置き換え可能」が超大事です。 つまり「子は親として扱っても同じように動くべき」ってこと。
でも現場で起きるのは👇
- 「ちょっと似てるから」で継承しちゃう
- でも “親として扱う” と破綻する💥
例(超あるある):
- 「Bird(鳥)」を継承した「Penguin(ペンギン)」に fly() があると…?🐧💦 → “鳥なら飛べるはず” 前提が崩壊😇
📌ここが学び: 継承は「共通点がある」じゃ足りない。置き換え可能(振る舞いの契約) が必要🧾✨
2-5. 事故あるある⑤:protected で内臓むき出し🍖😱
親が protected フィールドや内部メソッドをいっぱい公開すると、子がそこに依存してしまう…🫠
すると親の内部変更ができなくなる=保守性が死ぬ💀
📌ここが学び: 継承は “仲良く見えて距離感ゼロ” になりやすい😇(あとで「部品として渡す」に変える🧩)
2-6. 事故あるある⑥:テストしづらい🧪😵
継承が深くなると…
- 生成するだけで重い(親の都合が乗る)🐘
- どこが原因か追いづらい(オーバーライド地獄)🌀
- 差し替えが難しい(new が固定)🔒
📌ここが学び: “テストが書きにくい設計” は、だいたい “変更もしにくい” 🥲
2-7. ミニ演習✍️✨「継承地獄の芽」を自分で見つける🕵️♀️
演習A:組み合わせ要求を3つ足してみる🧩🧩🧩
上の User/Admin の例に、次の要求を追加したいとします👇
- Admin の閲覧専用👀
- Admin の2段階認証🔐
- Admin のお試し期間⏳
✅やること: 「継承だけ」で頑張る場合、必要になるクラス名を 紙に列挙 してみてね📝 (たぶん途中で笑う😇)
演習B:親の変更で子が壊れる“想像テスト”🤯
✅やること:
BaseAuth の login() の中を、次のどれかに変えたら「子が壊れそう?」を考えてみてね👇
- 失敗時ロックの条件を変更🔐
- checkPassword を2回呼ぶように変更🔁
- 例外を握りつぶすように変更🧯
💡ポイント: 「親の変更は安全か?」を 親だけ見て判断できない のが怖さ😱 (ウィキペディア)
2-8. AI拡張(Copilot/Codex等)での学びブースト🤖✨
この章は「レビュー係」として AI が超便利💕
そのまま使えるお願い例🗣️💡
- 「この継承コードで、将来事故りそうな点を箇条書きで教えて」📝
- 「要求が増えたとき、クラス爆発が起きる理由を説明して」🌳💣
- 「この設計の依存関係の強さ(変更の伝染)を指摘して」🪢
AIの答えをチェックする観点👀✅
- “組み合わせ” が出てきてない?🧩
- 親の内部に子が依存してない?🍖
- 「置き換え可能」壊してない?🙅♀️
2-9. まとめ📌✨(この章で覚える合言葉)
- 継承は 共通化 というより 強い結びつき(契約) になりがち🪢
- 変更は伝染する🤒(Fragile Base Class) (ウィキペディア)
- 組み合わせが必要になった瞬間、継承ツリーは爆発しやすい🌳💣
- 「似てるから継承」は危険⚠️(置き換え可能が必要)
次章チラ見せ👀✨
次の第3章では、ここまでの地獄をぜんぶ救う基本ムーブ👇 「部品を持って、部品にお願いする(委譲)」🧩🙏 を、TypeScriptで気持ちよくやっていきます〜!🚑✨
(ちなみに TypeScript は今 “ネイティブ化(Project Corsa)” を進めていて、将来の 6.0/7.0 の話も公式に出てます📣) (devblogs.microsoft.com)