JSON→TypeScript変換
JSONを貼り付けて、TypeScriptインターフェースを瞬時に取得します。
使い方
- JSONを左側のパネルに貼り付けます(オブジェクトまたは配列)。
- 変換をクリック · TypeScriptインターフェースが右側に表示されます。
- 必要に応じてルート名を調整し、オプションを有効にします。
- 出力をコピーをクリックして、生成されたコードをコピーします。
よくある質問
ネストされたオブジェクトを処理しますか?
はい。各ネストされたオブジェクトには独自の名前付きインターフェースが付与されます。配列要素も型を決定するために分析されます。
混在型の配列はどうなりますか?
配列に異なる型の要素が含まれる場合、コンバーターはユニオン型(例: string | number)を使用します。
ルートでJSON配列をサポートしますか?
はい。ルート値が配列の場合、コンバーターはその要素を分析し、適切なインターフェースと配列の型エイリアスを生成します。
コンバーターが実際に行うこと
JSONを解析し、すべての値を走査して、形状を記述するTypeScriptの interface 宣言のセットを出力する。ネストされたオブジェクトはそれぞれ独自の名前付きinterfaceを得る。PascalCaseで親プロパティキーから導出され(user フィールドは User interfaceになる)。2つのネストされたオブジェクトが名前で衝突すると、2番目に数値サフィックスが付く(User、User2)。ルートでは、配列は type Root = RootItem[]; エイリアスと RootItem interfaceになり;オブジェクトは単一の Root interface(または「root name」フィールドに入力した名前)になる。
サンプルの入力と出力:
// Input
{
"id": 42,
"name": "Ada",
"active": true,
"tags": ["admin", "billing"],
"profile": { "bio": "Programmer", "link": null }
}
// Output
export interface Root {
id: number;
name: string;
active: boolean;
tags: string[];
profile: Profile;
}
export interface Profile {
bio: string;
link: unknown;
}
JSON → TypeScript 型マッピング
| JSON値 | 生成されたTS |
|---|---|
"hello" | string |
42 または 3.14 | number(TSには別の整数型がない) |
true / false | boolean |
null | unknown(コンバーターはフィールドがnullableなのか、このサンプルで欠落しているだけなのかを判断できない) |
[] | unknown[] |
[1, 2, 3] | number[] |
[1, "x"] | (number | string)[] |
{ "a": 1 } | 名前付き interface |
ルートレベルのオブジェクト配列の場合、コンバーターはすべてのアイテムのキーを1つの代表的なinterfaceにマージする。アイテムが同じ形状を共有している場合は適切な近似だが、形状が本当に異なる場合(例:異種のevents配列)は情報が失われる。その場合は生成後に判別共用体を手動で記述する必要がある。
オブジェクトに interface、ルート配列に type が使われる理由
公式TypeScript Handbookは一行のヒューリスティックを示している:「interface を使え。type の機能が必要になったときだけ切り替えよ。」どちらも構造的型付けで、どちらもオブジェクトの形状を記述できる。しかし interface はオブジェクト形状に有利だ。宣言マージ(interfaceを再開いてフィールドを追加)をサポートし、extends でクリーンに機能し、コンパイラエラーに名前で表示される。type エイリアスはプリミティブの共用体、複数型の交差、または非オブジェクトに名前をつける必要がある場合に必要となる。そのためルートレベルの配列はinterfaceではなく type Root = RootItem[]; エイリアスを使う。
命名について:コンバーターはレガシーの I プレフィックスなしのPascalCaseを使う(User であって IUser ではない)。最新のTSスタイルガイド(Google、Microsoft、Reactコミュニティ)はほぼ普遍的にプレフィックスを廃止している。プロパティ名はJSONキーと完全に一致する(JSONがcamelCaseならcamelCase、snake_caseならsnake_case)。有効なJS識別子でないキー(ハイフン、スペースを含む、または数字で始まる)は引用符で囲まれる:"foo-bar": string;。
このツールができないこと(限界を正直に)
単一のJSONの例は実際のスキーマより情報が少ないため、検出できれば望ましいいくつかのことが入力だけでは不可能だ:
- オプションフィールド。例のすべてのプロパティは必須になる。実際のAPIが時々フィールドを省略する場合は、
?を手動で追加する:email?: string;。または複数の例でコンバーターを実行して結果を共用体にする。 - nullable検出。例の
nullはunknownになる。コンバーターはフィールドが本当にnullable(string | null)なのか、このサンプルでたまたまnullだっただけなのかを判断できない。API契約に基づいて手動で調整する。 - 文字列リテラル共用体。値が
"active"のstatusフィールドはstringになり、"active" | "inactive" | "pending"にはならない。コンバーターは他の値を見ることができない。 - Date型検出。
"2024-04-12T10:00:00Z"のようなISO 8601文字列はstringのままだ。JavaScriptのDateはJSON型ではない。 - 判別共用体。ルート配列に異なる形状のアイテムが含まれる場合(異なる型のイベント、ポリモーフィックなレコード)、コンバーターはタグ付き共用体を生成する代わりにすべてのキーをひとつのinterfaceにマージする。本当に異種のデータには、手動で共用体を記述する必要がある。
- 数値精度。JavaScriptの
numberは253−1まで整数を正確に表現できる。JSON.parseで解析すると大きな整数IDは精度を失う。APIが64ビット整数を返す場合、最も安全なパターンは文字列として送信してstringとして型定義することだ。
このツールを使う場面
- 実際のAPIレスポンスからの型のブートストラップ。エンドポイントにアクセスしてJSONを貼り付け、interfaceの出発点を得る。オプションフィールドと文字列リテラルのために手動で調整する。
- 型のない外部SDKへの型の追加。古いJSライブラリの多くは型なしで出荷される。サンプルレスポンスから生成する方がドキュメントを読むより速い。
- フロントエンドとバックエンド間での型の共有。ひとつの正規の例から生成して両方のコードベースにコピーする(または公開された型パッケージ経由で共有)。
- JSコードベースのTypeScriptへの移行。アプリを流れる実際のデータから型を生成して、関数シグネチャに段階的に注釈を付ける。
- 設定ファイルの型の生成。厳格な型付けにより設定エラーをコンパイル時に検出できる。
- 内部データファイルの形状の文書化。生成されたinterfaceは機械可読なドキュメントとして機能する。
コードファースト vs スキーマファースト vs ダイレクト(このツールの位置付け)
ランタイムデータからTypeScript型を取得する3つの一般的なワークフロー:
- コードファーストのランタイムバリデーター:Zod、Yup、Effect Schema、Joi。JSでバリデータースキーマを記述すると、ランタイム解析と推論によるTypeScript型の両方が得られる。スキーマが信頼の源だ。検証が型と同様に重要な場合に最適。
- スキーマファースト:JSON SchemaまたはOpenAPI仕様を記述し、
quicktype、json-schema-to-typescript、openapi-typescriptなどのツールでTypeScript型を生成する。APIコントラクトが複数の言語にまたがる場合に最適。 - ダイレクトサンプル推論(このツール、およびquicktypeのplain-JSONモード):実際のデータを貼り付けて型を得る。最速のパス;ランタイムデータを型に対して検証するものがないため、検証保証は最も弱い。
適切な選択は、主に静的型チェックが関心事か(このツールが最適)、それともランタイム安全性も必要か(Zod / Effect Schemaを使う)によって異なる。
よくある間違い
- 生成された型を完成した仕様として扱う。これらは70%完成した出発点だ。オプションフィールドには
?、本当にnullableな箇所には| null、該当する場所には文字列リテラル共用体を追加する。 - APIにバリアントがある場合に単一の例から生成する。
emailが時々存在して時々しないuserオブジェクトは「emailは必須」として生成される。複数の例でコンバーターを実行して結果を共用体にするか、手動で編集する。 - すべてを
readonlyとして自動的にマークする。不変のデータフローには有用だが、変更するステートオブジェクトには誤りだ。readonlyトグルは慎重に使う。 - 大きな整数IDの精度を信頼する。JavaScriptの
numberは253−1が上限だ。64ビットIDには文字列として転送し、stringとして型定義する。 interfaceとtypeを混同する。異なるツール、異なるトレードオフ。TypeScript Handbookのヒューリスティックは「typeが提供する機能が必要になるまではinterfaceを使え」で、まさにこのツールが行っていることだ。- 機密JSONをサーバーサイドコンバーターに貼り付ける。実際のAPIレスポンスには顧客データ、認証情報、内部IDが含まれることが多い。ブラウザのみの変換(このツール)はデータをマシン上に保持する。
よくある質問
フィールドがすべて必須としてマークされた理由は?
単一のJSONの例ではどのフィールドが実際のAPIで時々省略されるかをコンバーターに伝えられないからだ。例に現れるすべてのキーが必須になる。フィールドがオプションとわかっている場合は手動で末尾に ? を追加する:email?: string;。複数サンプルのオプション性検出には、より高機能な quicktype CLIがネイティブに対応している。
nullフィールドが unknown と型付けされる理由は?
単一のnullからコンバーターはフィールドが常にnullable(string | null)なのか、このサンプルでたまたまnullだっただけ(string)かを判断できないからだ。unknown が保守的なデフォルトで;TypeScriptは値を使う前に型を絞り込むことを強制する。これは any より安全だ。APIの意図がわかったら string | null に手動で編集する。
interface と type どちらを使うべきですか?
公式TypeScript Handbookのヒューリスティック:interface を使い、主に共用体型、交差型、またはプリミティブに名前をつけるなど type のみが提供する機能が必要なときだけ切り替える。このコンバーターはそのルールに従う:すべてのオブジェクト形状には interface、ルート配列エイリアスには type。一部のスタイルガイドはデフォルトで type を使うことを推奨しているが(Matt Pocockが公に主張している)、慣例的なデフォルトはオブジェクトにはinterfaceだ。
JSONはどこかにアップロードされますか?
いいえ。変換は JSON.parse でJSONを解析し、値を走査してTypeScriptの出力をtextareaに書き込む自己完結型のJavaScript IIFEだ。fetchも、JSONコンテンツを運ぶアナリティクス呼び出しも、サーバーも存在しない。実際のAPIレスポンスには顧客データ、内部ID、認証情報が含まれることが多く、第三者を経由させたくないため、これは重要だ。
JSDoc、Zod、またはランタイム検証はどうですか?
このツールはコンパイル時のTypeScript型のみを出力する:ランタイムバリデーターなし(Zod / Yup / Effect Schemaなし)、JSDocコメントなし。ランタイム検証と静的型の両方が必要な場合は、Zodでスキーマを記述して z.infer<typeof Schema> で型を導出する。JSON SchemaがありランタイムとTS型の両方が必要なら、json-schema-to-typescript + AJVが慣例的なペアリングだ。
interfaceの名前に I プレフィックスがない理由は?
最新のTypeScriptスタイルガイドのほとんどがそれを廃止しているからだ。GoogleのTypeScript Style Guideは明示的に推奨しない;Reactコミュニティはプレフィックスなしのパスカルケースに収束している。レガシーの IUser 規約は初期TypeScriptへのC# / Javaの影響から来ており、現在の慣行はシンプルな User だ。