Skip to content

🚀 Feature Request: Support multi-schema compilation with cross-file type deduplication (aggregate / project mode) #677

@KishoreKaushal

Description

@KishoreKaushal

🚀 Feature Request: Support multi-schema compilation with cross-file type deduplication (aggregate / project mode)

Summary

json-schema-to-typescript currently treats each schema input as an isolated compilation unit. When multiple schemas reference the same shared definitions (via $ref), generating TypeScript types from each schema independently results in duplicate interface definitions across output files.

This makes it difficult to use the tool for schema-driven contract repositories where:

  • Schemas are split across multiple YAML files
  • Shared base types (e.g. BaseEntity) are reused via $ref
  • Consumers expect a single, canonical TypeScript type identity

Problem Description

Consider a common schema layout:

schemas/
├── common.yaml        # BaseEntity, EntityId, shared primitives
├── clinic.yaml
├── clinic.view.yaml
├── clinic.create.yaml
└── clinic.update.yaml

common.yaml defines shared types:

$defs:
  BaseEntity:
    type: object
    properties:
      schemaVersion:
        type: string
        const: "v1"

Other schemas reuse it:

allOf:
  - $ref: "common.yaml#/$defs/BaseEntity"
  - type: object
    properties:
      id:
        type: string

When running:

json-schema-to-typescript clinic.yaml        --output clinic.ts
json-schema-to-typescript clinic.view.yaml   --output clinic.view.ts

Each output file redefines BaseEntity, even though the $ref points to the same external definition.

This leads to:

  • Duplicate interface definitions
  • No shared type identity across files
  • Inability to safely compose types in TypeScript
  • Broken “single source of truth” contract semantics

This means that json-schema-to-typescript currently has no project-level symbol graph or cross-file reuse model.


Why This Matters (Use Case)

This limitation makes it hard to use json-schema-to-typescript in:

  • Domain contract repositories
  • Schema-first backend/frontend architectures
  • Long-lived systems with versioned schemas
  • Migration-aware models (e.g. schemaVersion fields)

In these setups, shared base types are fundamental, and duplication breaks correctness, not just aesthetics.


Parallel: datamodel-code-generator (Python)

For reference, the Python tool datamodel-code-generator solves this exact problem by supporting:

  • Directory-level input
  • Model reuse via a shared symbol graph
  • Cross-file deduplication
  • A single generation pass that produces multiple modules with shared imports

Example flags:

datamodel-codegen \
  --input schemas/ \
  --reuse-model \
  --reuse-scope tree \
  --module-split-mode single

This ensures:

  • BaseEntity is generated once
  • Other models import it instead of redefining it

A similar concept (not necessarily identical implementation) would unlock powerful new use cases for json-schema-to-typescript.


Proposed Enhancement (High-Level)

Introduce an optional “aggregate / project mode”, for example:

  • A single root schema that references others (explicit aggregation)
  • Or a directory-based input mode with a unified symbol table
  • Or an option to emit imports instead of inlining shared definitions

Important:
This would be opt-in, preserving the current behavior by default.


Why This Is Not a Workaround Request

This issue is not asking for:

  • string-based de-duplication
  • cosmetic changes
  • relaxed validation

It is about type identity correctness when working with multiple schemas that intentionally share definitions.


Closing Thoughts

json-schema-to-typescript is an excellent tool and works extremely well for single-schema workflows. This feature request is about scaling it to multi-schema, contract-driven systems, where shared identity and reuse are essential.

Happy to help with:

  • design discussion
  • testing
  • documentation
  • concrete examples

Thanks for considering!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions