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

Standalone union of strings only created with 'definitions', not '$definitions' #470

Closed
JoshuaKGoldberg opened this issue Jul 28, 2022 · 2 comments

Comments

@JoshuaKGoldberg
Copy link
Contributor

JoshuaKGoldberg commented Jul 28, 2022

Hi! I'm trying to work on typescript-eslint/typescript-eslint#5386 (typescript-eslint/typescript-eslint#5058) to auto-generate typescript-eslint's rule docs options. We have a schema that reduces to something like this:

{
  "$definitions": {
    "shared": {
      "enum": ["a", "b"]
    }
  },
  "properties": {
    "first": {
      "$ref": "#/$definitions/shared"
    },
    "second": {
      "$ref": "#/$definitions/shared"
    }
  },
  "additionalProperties": false,
  "title": "Example Schema",
  "type": "object"
}
Quick Node script that compiles the schema...
var { compile } = require("json-schema-to-typescript");

var schema = {
  $definitions: {
    shared: {
      enum: ["a", "b"],
    },
  },
  properties: {
    first: {
      $ref: "#/$definitions/shared",
    },
    second: {
      $ref: "#/$definitions/shared",
    },
  },
  type: "object",
};

var pendingResult = compile(schema, "example", {
  additionalProperties: false,
  bannerComment: "",
  declareExternallyReferenced: true,
});

pendingResult.then((result) => console.log(result));

For context, a rule that shows this bug in its docs is: https://github.com/typescript-eslint/typescript-eslint/blob/029c2a8b0ea435922ad0643a4b22bef3cc05f55e/packages/eslint-plugin/src/rules/array-type.ts#L105.

Actual

export interface Example {
  first?: "a" | "b";
  second?: "a" | "b";
}

Expected

export type Shared = "a" | "b";

export interface Example {
  first?: Shared;
  second?: Shared;
}

Adding "tsType": "Shared" to the shared object makes it assume there exists a Shared type somewhere (note the lack of type Shared):

export interface Example {
  first?: Shared;
  second?: Shared;
}

Switching declareExternallyReferenced off or on doesn't seem to help.

Is this a bug or a feature request? 😄

@bcherny bcherny added the bug label Jul 28, 2022
@JoshuaKGoldberg JoshuaKGoldberg changed the title No way to create standalone union of strings Standalone union of strings only created with 'definitions', not '$definitions' Jul 29, 2022
@JoshuaKGoldberg
Copy link
Contributor Author

Update: just found that if we remove the $ from definitions, it correctly creates the export type Shared = "a" | "b". Fascinating.

{
  "definitions": {
    "shared": {
      "enum": ["a", "b"]
    }
  },
  "properties": {
    "first": {
      "$ref": "#/definitions/shared"
    },
    "second": {
      "$ref": "#/definitions/shared"
    }
  },
  "additionalProperties": false,
  "title": "Example Schema",
  "type": "object"
}
export type Shared = "a" | "b";

export interface Example {
  first?: Shared;
  second?: Shared;
}

@bcherny
Copy link
Owner

bcherny commented Aug 7, 2022

Hey! $definitions isn't a valid JSON-schema keyword. You want definitions (legacy) or $defs (preferred).

See https://json-schema.org/draft/2019-09/release-notes.html#semi-incompatible-changes

Tracking being more aggressive about warning about invalid keywords in #471

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

No branches or pull requests

2 participants