本文へスキップ

TypeScriptからJSONスキーマへの変換 — Numio

ts-json-schema-generator を使って TypeScript の型から draft-07 の JSON Schema を生成します。すべての型は "definitions" の下に置かれます。省略可能なプロパティは "required" に含まれず、オブジェクトには "additionalProperties": false が付きます。

リクエストとレスポンスの型が TypeScript の interface で定義されており、Ajv での検証や API ゲートウェイ用に JSON Schema が必要な場合。

TypeScript

JSON Schema

こんなときに使えます

  • リクエストとレスポンスの型が TypeScript の interface で定義されており、Ajv での検証や API ゲートウェイ用に JSON Schema が必要な場合。
  • 構造がすでに TypeScript の型で定義されている JSON 設定ファイルのスキーマを公開したい場合。

使い方

  1. TypeScript の interface か型エイリアスを貼り付けます。@minimum、@format、@pattern などの JSDoc タグはスキーマに取り込まれます。
  2. ソースは /api/typescript-to-json-schema に送信され、サーバー上で一時ファイルに書き出されてから、すべての型を公開する設定で処理されます。
  3. JSON Schema をコピーします。入力に型が 1 つしかない場合は、ルートにもその型への $ref が付きます。

TypeScript

/** A product in the catalog */
export interface Product {
  /** @minimum 0 */
  price: number;
  name: string;
  tags?: string[];
}

JSON Schema (draft-07)

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/Product",
  "definitions": {
    "Product": {
      "type": "object",
      "properties": {
        "price": {
          "type": "number",
          "minimum": 0
        },
        "name": {
          "type": "string"
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "price",
        "name"
…

仕様と制限

入力は変換のためにサーバーのルート(/api/typescript-to-json-schema)に送信されます。ブラウザ内だけで処理されるわけではありません。Next.js の API ルートが受け付けるリクエストボディは、デフォルトで 1 MB までです。

JSDoc は拡張モードで解析されます。説明コメントは "description" に、@minimum 0 や @minLength 1 のようなタグはキーワードになります。

interface のメソッドはスキップされます。Date は format が date-time の string に、リテラルのユニオン型は enum になります。

bigint には対応しておらず、"Unknown node" エラーになります。Map と Set はその interface、つまり数値の size だけを持つオブジェクトとして記述されるため、JSON データには Record<string, T> か配列を使ってください。

FAQ

エクスポートされていない型も含まれますか?

はい。入力内のすべての型が、エクスポートの有無にかかわらず "definitions" に追加され、型同士の参照には $ref が使われます。

省略可能なプロパティと null 許容のプロパティはどう表現されますか?

省略可能なプロパティは "required" に含まれません。null とのユニオン型は {"type": "null"} を含む anyOf になります。

なぜルートに $ref があるのですか?

型が 1 つだけの場合、ジェネレーターは $ref でルートをその型に向けます。型が複数ある場合は "definitions" だけが出力されます。

仕様を確認する