TypeScript デザインパターン
GoF のデザインパターンを、現代の TypeScript で書くならどうなるかという観点で読み直すガイドです。
このガイドについて
デザインパターンの多くは、クラスと継承を中心に据えた言語を前提に整理されました。TypeScript には第一級関数、判別可能ユニオン、構造的部分型があり、同じ目的をクラス階層なしで達成できる場面があります。
そこで本ガイドは、パターンの解説に加えて そのパターンが TypeScript でも必要かどうか を各章で判定します。判定は「言語機能で代替できる」で終わらせず、クラスとして書き続ける価値が残る条件も必ず並べて示します。
対象読者は、TypeScript でクラスとインターフェースを書いた経験があり、設計の選択肢を増やしたい人です。文法そのものは TypeScript ガイド、コード品質の規範は クリーンコードガイド で扱っています。
各章の構成
すべてのパターン章を同じ 5 つの節で構成します。事実と編集判断を混ぜないための約束です。
| 節 | 書くこと |
|---|---|
| このパターンが解こうとした問題 | そのパターンが定めた意図と適用条件。出典を示します |
| クラスで素直に書く | パターンどおりの TypeScript 実装 |
| 言語機能で置き換える | 代わりに使える言語機能。仕様やドキュメントの出典を示します |
| 本連載の判断 | ここだけが編集判断です。 言語機能で足りる条件と、クラスのまま書く条件を並べます |
| 既存記事との関係 | 同じ題材を扱った既存記事へのリンク |
判定は「言語機能で代替できる」「条件付き」「クラス実装を推奨」の 3 つのいずれかで示します。判定は事実ではなく本ガイドの立場なので、根拠と、その判定が覆る条件をあわせて書きます。
生成に関するパターン
| 章 | パターン | 扱うこと |
|---|---|---|
| 01 | Singleton | ES モジュールが単一インスタンスを与える範囲と、その境目 |
| 02 | Factory Method と Abstract Factory | 生成を関数に寄せられる条件 |
| 03 | Builder | リテラルで足りる場合と、型で段階的な必須を表す場合 |
構造に関するパターン
| 章 | パターン | 扱うこと |
|---|---|---|
| 04 | Adapter | 構造的部分型が消す境界 |
| 05 | Decorator | TypeScript の Decorators 構文とは別概念であること |
| 06 | Proxy | 組み込みの Proxy と同じ名前の別概念であること |
| 07 | Composite | 再帰的な判別可能ユニオンで木を表す |
振る舞いに関するパターン
| 章 | パターン | 扱うこと |
|---|---|---|
| 08 | Strategy | 関数を渡すだけで足りる範囲 |
| 09 | Observer | EventTarget と AbortSignal でどこまで足りるか |
| 10 | State | 不正な遷移を型で禁止する |
| 11 | Template Method | 継承による骨組み固定とフック関数の注入 |
| 12 | Iterator | 言語仕様に取り込まれた反復の抽象化 |
| 13 | Visitor | 網羅チェックが引き取る役割 |
| 14 | Chain of Responsibility | ミドルウェアという形と、型による文脈の受け渡し |
GoF の外にあるパターンと総括
| 章 | 内容 |
|---|---|
| 15 | Repository。GoF ではなく PoEAA に由来するパターンを、型で表現する側面から扱います |
| 16 | 章を立てなかったパターンの短評と、判定の一覧 |
独立した章を設けなかったパターン
23 パターンをすべて同じ密度で扱うと分量が破綻するため、TypeScript の観点で議論の余地が大きいものに絞りました。次の 8 つは独立した章を設けず、まとめで短く扱います。この取捨は本ガイドの編集判断です。
| パターン | 章を設けなかった理由 |
|---|---|
| Prototype | 複製の手段が主題で、章 1 本に広げるだけの論点がないためです |
| Facade | 公開する範囲を絞る話が中心で、モジュール設計の話題に寄るためです |
| Command | データとして表す形が Visitor の章と重なり、既存記事も別の文脈で扱っているためです |
| Bridge | 抽象と実装を分ける説明が Strategy や Adapter と重なりやすいためです |
| Flyweight | 共有によるメモリ削減が主題で、実行環境の挙動の話に寄るためです |
| Mediator | 仲介役を置くという構造そのものに TypeScript 固有の論点が出にくいためです |
| Memento | 状態の保存と復元が主題で、Prototype と同じ道具に行き着くためです |
| Interpreter | 構文木の評価が主題で、Visitor の章で扱う内容と重なるためです |