bcherny / json-schema-to-typescript

Compile JSON Schema to TypeScript type declarations
https://bcherny.github.io/json-schema-to-typescript-browser/
MIT License
2.92k stars 392 forks source link

$ref inheritance not supported #613

Open JBBianchi opened 2 months ago

JBBianchi commented 2 months ago

When modeling inheritance, we can use $ref to point to an existing definition and extend it.

e.g.:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Sample",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "neighborhood": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/person"
      }
    }
  },
  "$defs": {
    "baseType": {
      "title": "BaseType",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    },
    "person": {
      "title": "Person",
      "$ref": "#/$defs/baseType",
      "type": "object",
      "unevaluatedProperties": false,
      "properties": {
        "age": {
          "type": "number"
        }
      }
    }
  }
}

and the expected output to be equivalent to:

export interface Sample {
  neighborhood?: Person[];
}
export interface Person extends BaseType {
  age?: "number";
}
export interface BaseType {
  name?: string;
}

But with the provided code, the output of json-schema-to-typescript (14.1) with default options will be erroneous:

Here is the generated output with the default settings:

export interface Sample {
  neighborhood?: Person[];
}
export interface Person {
  age?: "number";
  [k: string]: unknown;
}

Even by enabling unreachableDefinitions, the output isn't better. BaseType appears but it's still not used properly.

export interface Sample {
  neighborhood?: Person[];
}
export interface Person {
  age?: "number";
  [k: string]: unknown;
}
/**
 * This interface was referenced by `Sample`'s JSON-Schema
 * via the `definition` "baseType".
 */
export interface BaseType {
  name?: string;
  [k: string]: unknown;
}
/**
 * This interface was referenced by `Sample`'s JSON-Schema
 * via the `definition` "person".
 */
export interface Person1 {
  age?: "number";
  [k: string]: unknown;
}

The closest schema that would produce something close to the expected result would be:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Sample",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "neighborhood": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/person"
      }
    }
  },
  "$defs": {
    "baseType": {
      "title": "BaseType",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    },
    "person": {
      "title": "Person",
      "type": "object",
      "allOf": [
        { "$ref": "#/$defs/baseType" },
        {
          "properties": {
            "age": {
              "type": "number"
            }
          },
          "unevaluatedProperties": false
        }
      ]
    }
  }
}

Edit: I removed a part I was talking about using additionalProperties to store the $ref but I was mistaken, it's not the same behavior.

petrosv91 commented 3 weeks ago

Any update on that? I have the same issue.