
開発のきっかけ:ある午後の「虚無感」
モダンなWeb開発において、フロントエンドエンジニアの仕事の半分は「APIとの対話」だと言っても過言ではありません。PostmanやSwaggerでAPIのレスポンスを確認し、それをTypeScriptの interface や type に書き起こす――。
ある日の午後、複雑な階層を持つ巨大なJSONレスポンスを眺めながら、私はふと指を止めました。
「私は今、一体何のためにプロパティ名を一字一句打ち込んでいるんだ? この作業に、エンジニアとしての創造性はあるのか?」
プロジェクトが大きくなるほど、レスポンスの階層は深くなり、タイポ(打ち間違い)のリスクも増えていきます。そんな「単純作業」から自分自身を解放したい。
「設定不要で、貼り付けた瞬間に、納得感のある型が手に入る」。そんな「職人の道具」のような手触りのツールが欲しくて、JSON to TypeScript型生成ツール の開発をスタートしました。
技術的な工夫:再帰アルゴリズムという「美学」
このツールの最大の挑戦は、**「外部の重いライブラリを一切使わず、純粋なロジックだけでプロレベルの精度を実現する」**ことでした。
1. 終わりのない階層を巡る「再帰処理」
JSONは、箱の中にまた箱が入っているような、入れ子構造をしています。どれだけ深くネストしていても、一瞬で最深部まで辿り着かなければなりません。この「不定形の深さ」に対応するため、アルゴリズムは純粋な再帰処理で構築しました。
private static inferType(value: any, depth = 1): string {
// プリミティブ型の判定は基本
if (value === null) return 'null';
// 配列の場合は中身をまた全探索
if (Array.isArray(value)) return this.formatArray(value, depth);
// オブジェクトの場合はプロパティを再帰的に巡回
if (typeof value === 'object') return this.formatObject(value, depth);
return typeof value;
}
このシンプルな構造を磨き上げることで、どんなに複雑なデータ構造でも、一瞬で壊れにくい型定義を生成できるようになりました。
2. 「Union型」へのこだわり
開発中に最も頭を悩ませたのは配列の扱いです。
例えば [1, "text", null] という配列があった場合、単に any[] と出力するのはあまりに投げやりです。かといって、先頭の要素だけを見て number[] と決めてしまうのも不親切きわまりない。
本ツールでは、配列内のすべての要素の型を一度洗い出し、重複を排除した上で |(パイプ)で結合したUnion型として出力するロジックを組み込みました。
const types = Array.from(new Set(arr.map(item => this.inferType(item))));
const union = types.length === 1 ? types[0] : `(${types.join(' | ')})`;
return union + '[]'; // 結果: (number | string | null)[]
この「ちょっとした気の利き方」こそが、実際の開発現場での使い心地を大きく左右すると確信しています。
「見えないところ」への配慮
変換結果の「美しさ」にもこだわりました。
インデントの深さやキー名のクォート処理など、「変換されたコードをそのままプロジェクトに貼り付けて、一度もフォーマッターをかけずにコミットできる」レベルの品質を目指し、細かな文字調整を繰り返しました。
最後に
JSON→TypeScript変換ツールは、一見すると地味なツールです。しかし、その裏側には「再帰処理の美しさ」と、「エンジニアの時間を1分でも無駄にさせない」という強いこだわりが詰まっています。
あなたの開発時間を、単なる「型の書き起こし」から「価値あるコードの構築」へとシフトさせる。そのための小さな力になれることを願っています。