Skip to content

Latest commit

History

History
60 lines (48 loc) 路 2.21 KB

does-json-schema-to-ts-work-on-json-file-schemas.md

File metadata and controls

60 lines (48 loc) 路 2.21 KB

Does json-schema-to-ts work on .json file schemas?

Sadly, no 馃槶

FromSchema is based on type computations. By design, it only works on "good enough" material, i.e. narrow types ({ type: "string" }) and NOT widened ones ({ type: string } which can also represent { type: "number" }). However, JSON imports are widened by default. This is native TS behavior, there's no changing that.

If you really want use .json files, you can start by upvoting this feature request to implement .json imports as const on the official repo 馃檪 AND you can always cast imported schemas as their narrow types:

// dog.json
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer" },
    "hobbies": { "type": "array", "items": { "type": "string" } },
    "favoriteFood": { "enum": ["pizza", "taco", "fries"] }
  },
  "required": ["name", "age"]
}
import { FromSchema } from "json-schema-to-ts";

import dogRawSchema from "./dog.json";

const dogSchema = dogRawSchema as {
  type: "object";
  properties: {
    name: { type: "string" };
    age: { type: "integer" };
    hobbies: { type: "array"; items: { type: "string" } };
    favoriteFood: { enum: ["pizza", "taco", "fries"] };
  };
  required: ["name", "age"];
};

type Dog = FromSchema<typeof dogSchema>;
// => Will work 馃檶

It is technically code duplication, BUT TS will throw an errow if the narrow and widened types don't sufficiently overlap, which allows for partial type safety (roughly, everything but the object "leafs"). In particular, this will work well on object properties names, as object keys are not widened by default.

import { FromSchema } from "json-schema-to-ts";

import dogRawSchema from "./dog.json";

const dogSchema = dogoRawSchema as {
  type: "object";
  properties: {
    name: { type: "number" }; // "number" instead of "string" will go undetected...
    years: { type: "integer" }; // ...but "years" instead of "age" will not 馃檶
    hobbies: { type: "array"; items: { type: "string" } };
    favoriteFood: { const: "pizza" }; // ..."const" instead of "enum" as well 馃檶
  };
  required: ["name", "age"];
};