ts-json-schema-generator
ts-json-schema-generator copied to clipboard
fix: inline purely structural generics
Partially closes #2233
When a type alias with generic parameters ultimately resolves to a purely structural type (no remaining type-parameters, no public reusable symbol), emitting it as a separate $ref just clutters the schema tree.
This PR detects those cases and inlines the resolved structure directly into the parent definition, collapsing long reference chains and trimming unused definitions.
Examples
Case 1 — Mapped/Override helper
import { OverrideProperties } from "./util";
export type Base = {
foo: string;
bar: number;
};
export type MyType = OverrideProperties<
Base,
{
bar: string;
}
>;
Before
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Base": { /* ... */ },
"Merge<Base,structure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192>": {
"$ref": "#/definitions/Simplify%3C(alias-1249507601-457-604-1249507601-0-1064%3Cdef-alias-1249507601-129-293-1249507601-0-1064%3Cdef-alias-303496744-44-103-303496744-0-192%3E%2Cdef-alias-1249507601-129-293-1249507601-0-1064%3Cstructure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192%3E%3E%26alias-1249507601-457-604-1249507601-0-1064%3Cdef-alias-1249507601-293-457-1249507601-0-1064%3Cdef-alias-303496744-44-103-303496744-0-192%3E%2Cdef-alias-1249507601-293-457-1249507601-0-1064%3Cstructure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192%3E%3E)%3E"
},
"MyType": {
"$ref": "#/definitions/OverrideProperties%3CBase%2Cstructure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192%3E"
},
"OverrideProperties<Base,structure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192>": {
"$ref": "#/definitions/Merge%3CBase%2Cstructure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192%3E"
},
"Simplify<(alias-1249507601-457-604-1249507601-0-1064<def-alias-1249507601-129-293-1249507601-0-1064<def-alias-303496744-44-103-303496744-0-192>,def-alias-1249507601-129-293-1249507601-0-1064<structure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192>>&alias-1249507601-457-604-1249507601-0-1064<def-alias-1249507601-293-457-1249507601-0-1064<def-alias-303496744-44-103-303496744-0-192>,def-alias-1249507601-293-457-1249507601-0-1064<structure-303496744-155-188-303496744-125-190-303496744-103-191-303496744-0-192>>)>": {
"additionalProperties": false,
"properties": {
"bar": { "type": "string" },
"foo": { "type": "string" }
},
"required": ["bar", "foo"],
"type": "object"
}
}
}
After
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Base": { /* ... */ },
"MyType": {
"additionalProperties": false,
"properties": {
"bar": { "type": "string" },
"foo": { "type": "string" }
},
"required": ["bar", "foo"],
"type": "object"
}
}
}
Case 2 — ValueOf on a const object
export const RuntimeObject = {
FOO: "foo-val",
BAR: "bar-val",
} as const;
export type ValueOf<T> = T[keyof T];
export type MyType = ValueOf<typeof RuntimeObject>;
Before
{
"$ref": "#/definitions/MyType",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"MyType": {
"$ref": "#/definitions/ValueOf%3Cobject-810933776-28-72-810933776-28-81-810933776-12-81-810933776-6-81-810933776-0-82-810933776-0-174%3E"
},
"ValueOf<object-810933776-28-72-810933776-28-81-810933776-12-81-810933776-6-81-810933776-0-82-810933776-0-174>": {
"enum": ["foo-val", "bar-val"],
"type": "string"
}
}
}
After
{
"$ref": "#/definitions/MyType",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"MyType": {
"enum": ["foo-val", "bar-val"],
"type": "string"
}
}
}
Inlining these internal generics is safe: the generator already skips emitting them as standalone definitions - even if you'd request type: "OverrideProperties" - so this change only cleans the schema output without dropping any functionality.