Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identical properties with same title generate multiple types #510

Open
jemand771 opened this issue Feb 14, 2023 · 1 comment
Open

Identical properties with same title generate multiple types #510

jemand771 opened this issue Feb 14, 2023 · 1 comment

Comments

@jemand771
Copy link

Example: A rectangle schema with two corners. Both corners are the same type and most importantly share a title.

I know this isn't an ideal schema (should ref in the points), but sometimes you just get bad data from somewhere.

import { compile } from 'json-schema-to-typescript';
import * as fs from 'node:fs';

const schema = {
    type: "object",
    title: "rectangle",
    properties: {
        p1: {
            type: "object",
            title: "point",
            properties: {
                x: "number",
                y: "number"
            },
            required: ["x", "y"]
        },
        p2: {
            type: "object",
            title: "point",
            properties: {
                x: "number",
                y: "number"
            },
            required: ["x", "y"]
        }
    },
    required: ["p1", "p2"]
}

fs.writeFileSync("dupe-example.ts", await compile(schema, undefined, { additionalProperties: false, bannerComment: "" }))

this turns into

export interface Rectangle {
  p1: Point;
  p2: Point1;
}
export interface Point {
  x: "number";
  y: "number";
}
export interface Point1 {
  x: "number";
  y: "number";
}

which is correct, I guess? after all, I'm putting garbage in and get garbage out. I'd prefer to get something like

export interface Rectangle {
  p1: Point;
  p2: Point;
}
export interface Point {
  x: "number";
  y: "number";
}

but I'm not sure if that's in the scope of this project. I saw #456, but as far as I understand it, that only allows changing the interface name before1 the incrementing number is appended, not after (so the same as just setting the title).

Ideally, I'd want a way to hard override the generated interface name. "Trust me, this is a Point, don't complain about duplicates"2.
As a more complex alternative, this package could "detect" identical properties (with or without matching titles) and reuse the interfacces generated from those. Again, this might be out of scope - we're starting to shift from parse+generate into ✨ magic ✨

Any advice? I'd also be fine with a hacky workaround, can't be worse than regexing through my .ts file3 :^)

Footnotes

  1. see https://github.com/bcherny/json-schema-to-typescript/pull/456/files#diff-abe2818e9c29aadf84401cb7ef8286c7cbce9253eba09f6fa52e22ca4e57b17eR303-R305 - generateName is called after the override and adds a counter

  2. I'm already committing a kind of crime here: I take in lots of schemas and compile them individually, all into one file. I run ts-dedupe on that file which gets rid of interfaces with the same name. This helps a lot when multiple schemas define a "title": "point" somewhere, but can't duplicates within a schema by itself. ts-dedupe only compares interface names, not their contents/definitions.

  3. As a final note: I don't have to have neat types, since I can just create my own Point interface and use that everywhere. After all, typescript will let identical types from different definitions "fit onto" each other. As long as nobody looks at the schemas' type definitions, the 10 different PointXX interfaces aren't noticable

@bcherny
Copy link
Owner

bcherny commented Feb 19, 2023

As you suggested, this is expected behavior.

One approach you suggested could work: if two schemas are (a) identical and (b) have the same explicit title, then emit just one type to represent the schema. We could implement this as a normalizer step that mutates a schema to instead be a $ref to the property it duplicates. Happy to stamp a PR if you'd like to take a pass at this.

ianfuin pushed a commit to ianfuin/json-schema-to-typescript that referenced this issue Feb 24, 2023
If two schemas are (a) identical and (b) have the same explicit title, then emit just one type to
represent the schema

fix bcherny#510
ianfuin pushed a commit to ianfuin/json-schema-to-typescript that referenced this issue Feb 24, 2023
If two schemas are (a) identical and (b) have the same explicit title, then emit just one type to
represent the schema

fix bcherny#510
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants