【テクニカル・上級編】引数に渡す関数の「引数の数(Arity)」を型レベルで制限するテクニック – TypeScript コア・型システムの基礎解析バイブル

TypeScriptを掌握する極限の知見:Arity(引数の数)を型レベルで強制するコンパイラ駆動設計

チーフシステムアーキテクトの視点から言えば、現代のTypeScript開発において最も見落とされている脆弱性、あるいは設計上の負債は「関数の過剰な引数受容(Arity mismatch)」にある。

例えば、`Array.prototype.map(callback)` に無防備に任意の関数を渡したとき、ランタイムは何を考えているか。JavaScriptのエンジン(V8など)は、呼び出されたコールバックに対し、インデックスや配列本体といった余計な引数を暗黙的に流し込む。`.map(parseInt)` が奇妙な挙動を示すのは周知の通りだ。

今回は、このランタイムの「お節介」をコンパイルタイムの型システムで完全にハックし、高階関数に渡すコールバックの引数の数(Arity)を厳密に制限・強制するテクニックを解説する。これは単なる型パズルではない。巨大なコードベースにおける意図しない副作用の伝播を防ぎ、V8のインラインキャッシュ(IC)を汚染させないための防壁構築なのだ。

—

1. 型システムにおける「引数リスト」の解体と評価

TypeScriptの関数型は、単なるシグネチャではない。コンパイラ内部(`checker.ts`)において、関数型は `FunctionType` という構造を持ち、そのパラメータリストは `Parameters` というタプル型として露出する。

私たちが目指すべきは、渡された関数 `F` のパラメータタプルの長さを `extends` キーワードを用いて静的に評価し、許容される上限(あるいは正確な数)を超えている場合に `never` やコンパイルエラーを誘発することだ。

しかし、単純に `Parameters[‘length’]` を見ても、可変長引数(Rest Parameters)を持つ関数に対して無力であるか、あるいは不正確な評価を下してしまう。厳密なArity制御には、タプルの構造解析における極限の最適化が必要となる。

—

2. 実装:厳密なArity制限を持つ高階関数の型定義

以下のコードを見てほしい。ここでは、引数を最大2つまでしか受け取らない関数のみを安全に受け入れる高階関数 `secureMap` の実装と、その型定義の全貌である。

type

タイトルとURLをコピーしました