principle-type-system-discipline について
複数の型付き言語で、型システムを使って不正な状態を排除し、コンパイル時にエラーを見つける開発スキルです。データモデル、境界での検証、網羅的なパターンマッチを扱います。
主な機能
- 01不正な状態を明示的なバリアントで表現
- 02意味を持つプリミティブ型にブランドを付与
- 03境界で型のないデータをパース
- 04危険なキャストや型変換を回避
- 05バリアントの網羅的なマッチを要求
- 06信頼できるスキーマから型を導出
活用シーン
- 01相互排他的な状態を安全に表現
- 02意味の異なる識別子を区別
- 03RPC、JSON、設定入力を検証
- 04新しいバリアントをコンパイル時に検出
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ poteto/ plugins --skill principle-type-system-disciplineインストール後、Claude Code で/principle-type-system-disciplineを入力して読み込まれたか確認します。
詳細
型システムの規律
型チェッカーは証明支援系です。不可能な状態、型の異なるプリミティブ、未処理のバリアントをコンパイル時に排除するために活用してください。実行時データとして通してしまったものは、コンパイラーが未然に防げたはずの実行時エラーになります。
型付き言語であれば、どの言語にも当てはまります。typescript-best-practices のようなスキルでは、具体的な構文に基づいて説明しています。
パターン:
- 不正な状態を表現できないようにします。 バリアントは積型としてモデル化します。TypeScript では判別可能なユニオン、Rust/Swift/Kotlin ではペイロード付きの列挙型、Scala ではシールドクラス、Haskell/OCaml では代数的データ型を使います。矛盾する組み合わせがコンパイルできてしまう、任意のオプションフィールドの寄せ集めとして状態をモデル化しないでください。名前を挙げておく価値のある、見落としやすいアンチパターンがあります。
{ completed: boolean; completedAt?: Date }では、意味のないcompleted: true; completedAt: undefinedが成立してしまいます。completedAt !== nullのような単一の情報源から真偽値を導出するか、{ kind: 'open' } | { kind: 'done'; at: Date }のようにバリアントを明示的にモデル化してください。バグによって「待って、この組み合わせは本当に起こり得るのか?」と考えさせられるなら、型が緩すぎます。 - 意味を持つプリミティブにブランドを付けます。
UserIdとOrderIdはどちらも内部的には文字列ですが、相互に置き換えられるべきではありません。Rust のニュータイプ、Swift の不透明型、Kotlin の値クラス、Haskell のファントム型、TypeScript のブランド付き交差型を使います。作成時に一度検証し、その後は型を信頼します。 - 外部データはパースされるまで型なしです。 RPC ペイロード、JSON、IPC メッセージ、CLI 引数、設定ファイル、環境変数、データベースの行などが該当します。すべての境界にパース関数を用意し、構造化されていない入力を型付きモデルに変換してください。検証をどこに置くかは、boundary-discipline 原則のスキルを参照してください。
- 型システムに嘘をつかないでください。 コンパイラーを迂回するキャスト、安全でない型強制、アサーション関数は、いつか実行時クラッシュを招きます。コンパイラーが事実を証明できないなら、その事実を証明するか(検証、型の絞り込み、モデルの精緻化)、キャストが危険であることを受け入れてください。今日隠したキャストは、来週書くことになる事後分析です。
- 網羅的なパターンマッチングはコンパイラーの仕事です。 積型に対してパターンマッチングを行うとき、新しいバリアントを追加したのに処理されていなければ、コンパイラーがコンパイルに失敗しなければなりません。各言語の慣用的な方法を使います。TypeScript では
never型のバインディング、Rust では注釈なしのmatch、Haskell では-Wincomplete-patterns、Kotlin ではシールドクラスの網羅性チェックです。 - 信頼できるスキーマから型を導出します。 プロトコルバッファー、OpenAPI 仕様、GraphQL スキーマ、データベースマイグレーション、デザインシステムのトークンファイルが形状を定義している場合は、独自に並行する型を手作業で作らず、そこから導出してください。手作業で重複させると、ずれが生じます。encode-lessons-in-structure 原則のスキルを参照してください。
- 実行時よりコンパイル時を優先します。 実行時アサーション、null チェック、
instanceofを使うたびに、型システムが十分に機能していないことを認めることになります。チェックを型の段階に移してください。
テスト項目:
- 「このフィールドの組み合わせが有効になる条件を、コメントで説明できますか?」できるなら、型が緩すぎます。積型に分割してください。
- 「関数の引数のうち、プリミティブ型は同じでも意味が異なるものはありますか?」ブランドを付けてください。
- 「この
any、このas、このassertNotNullはどこから来ましたか?」境界までさかのぼり、そこで検証してください。 - 「来月、新しいバリアントが追加されたら、次のエージェントにケースの追加場所をコンパイラーが知らせてくれますか?」知らせてくれないなら、そのマッチングは網羅的ではありません。
- 「この型は、別のファイルが所有する形状を重複して定義していますか?」重複を避け、そこから導出してください。
コメント
Markdown 対応