{"id":15012943,"url":"https://github.com/thomasaribart/json-schema-to-ts","last_synced_at":"2025-05-13T15:12:17.858Z","repository":{"id":38411474,"uuid":"279603897","full_name":"ThomasAribart/json-schema-to-ts","owner":"ThomasAribart","description":"Infer TS types from JSON schemas 📝","archived":false,"fork":false,"pushed_at":"2025-02-15T12:07:23.000Z","size":1619,"stargazers_count":1566,"open_issues_count":23,"forks_count":33,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-08T05:03:26.506Z","etag":null,"topics":["json","json-schema","schema","ts","type","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ThomasAribart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["ThomasAribart"]}},"created_at":"2020-07-14T14:12:24.000Z","updated_at":"2025-05-04T07:02:46.000Z","dependencies_parsed_at":"2024-06-18T12:24:13.233Z","dependency_job_id":"1fa993de-419a-4fb1-a419-5f767f3e2364","html_url":"https://github.com/ThomasAribart/json-schema-to-ts","commit_stats":{"total_commits":300,"total_committers":12,"mean_commits":25.0,"dds":"0.18000000000000005","last_synced_commit":"8968d7515e0d984f20dbf8f8f1669a5fd077babc"},"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThomasAribart%2Fjson-schema-to-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThomasAribart%2Fjson-schema-to-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThomasAribart%2Fjson-schema-to-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThomasAribart%2Fjson-schema-to-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThomasAribart","download_url":"https://codeload.github.com/ThomasAribart/json-schema-to-ts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253969264,"owners_count":21992263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","json-schema","schema","ts","type","typescript"],"created_at":"2024-09-24T19:43:27.689Z","updated_at":"2025-05-13T15:12:12.839Z","avatar_url":"https://github.com/ThomasAribart.png","language":"TypeScript","funding_links":["https://github.com/sponsors/ThomasAribart"],"categories":["Validation"],"sub_categories":["Runtime"],"readme":"\u003cimg src=\"assets/header-round-medium.png\" width=\"100%\" align=\"center\" /\u003e\n\n💖 _Huge thanks to the [sponsors](https://github.com/sponsors/ThomasAribart) who help me maintain this repo:_\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.theodo.fr/\"\u003e\u003cimg src=\"https://github.com/theodo.png\" width=\"50px\" alt=\"Theodo\" title=\"Theodo\"/\u003e\u003c/a\u003e\u003c/td\u003e\u0026nbsp;\u0026nbsp;\n  \u003c!-- sponsors --\u003e\u003ca href=\"https://github.com/feathersdev\"\u003e\u003cimg src=\"https://github.com/feathersdev.png\" width=\"50px\" alt=\"feathers.dev\" title=\"feathers.dev\"/\u003e\u003c/a\u003e\u0026nbsp;\u0026nbsp;\u003ca href=\"https://github.com/li-jia-nan\"\u003e\u003cimg src=\"https://github.com/li-jia-nan.png\" width=\"50px\" alt=\"lijianan\" title=\"lijianan\"/\u003e\u003c/a\u003e\u0026nbsp;\u0026nbsp;\u003ca href=\"https://github.com/RaeesBhatti\"\u003e\u003cimg src=\"https://github.com/RaeesBhatti.png\" width=\"50px\" alt=\"Raees Iqbal\" title=\"Raees Iqbal\"/\u003e\u003c/a\u003e\u0026nbsp;\u0026nbsp;\u003ca href=\"https://github.com/lucas-subli\"\u003e\u003cimg src=\"https://github.com/lucas-subli.png\" width=\"50px\" alt=\"Lucas Saldanha Ferreira\" title=\"Lucas Saldanha Ferreira\"/\u003e\u003c/a\u003e\u0026nbsp;\u0026nbsp;\u003ca href=\"https://github.com/syntaxfm\"\u003e\u003cimg src=\"https://github.com/syntaxfm.png\" width=\"50px\" alt=\"Syntax\" title=\"Syntax\"/\u003e\u003c/a\u003e\u0026nbsp;\u0026nbsp;\u003c!-- sponsors --\u003e\n  \u003ca href=\"https://github.com/sponsors/ThomasAribart\"\u003e\u003cimg src=\"assets/plus-sign.png\" width=\"50px\" alt=\"Plus sign\" title=\"Your brand here!\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Stop typing twice 🙅‍♂️\n\nA lot of projects use JSON schemas for runtime data validation along with TypeScript for static type checking.\n\nTheir code may look like this:\n\n```typescript\nconst dogSchema = {\n  type: \"object\",\n  properties: {\n    name: { type: \"string\" },\n    age: { type: \"integer\" },\n    hobbies: { type: \"array\", items: { type: \"string\" } },\n    favoriteFood: { enum: [\"pizza\", \"taco\", \"fries\"] },\n  },\n  required: [\"name\", \"age\"],\n};\n\ntype Dog = {\n  name: string;\n  age: number;\n  hobbies?: string[];\n  favoriteFood?: \"pizza\" | \"taco\" | \"fries\";\n};\n```\n\nBoth objects carry similar if not exactly the same information. This is a code duplication that can annoy developers and introduce bugs if not properly maintained.\n\nThat's when `json-schema-to-ts` comes to the rescue 💪\n\n## FromSchema\n\nThe `FromSchema` method lets you infer TS types directly from JSON schemas:\n\n```typescript\nimport { FromSchema } from \"json-schema-to-ts\";\n\nconst dogSchema = {\n  type: \"object\",\n  properties: {\n    name: { type: \"string\" },\n    age: { type: \"integer\" },\n    hobbies: { type: \"array\", items: { type: \"string\" } },\n    favoriteFood: { enum: [\"pizza\", \"taco\", \"fries\"] },\n  },\n  required: [\"name\", \"age\"],\n} as const;\n\ntype Dog = FromSchema\u003ctypeof dogSchema\u003e;\n// =\u003e Will infer the same type as above\n```\n\nSchemas can even be nested, as long as you don't forget the `as const` statement:\n\n```typescript\nconst catSchema = { ... } as const;\n\nconst petSchema = {\n  anyOf: [dogSchema, catSchema],\n} as const;\n\ntype Pet = FromSchema\u003ctypeof petSchema\u003e;\n// =\u003e Will work 🙌\n```\n\nThe `as const` statement is used so that TypeScript takes the schema definition to the word (e.g. _true_ is interpreted as the _true_ constant and not widened as _boolean_). It is pure TypeScript and has zero impact on the compiled code.\n\nIf you don't mind impacting the compiled code, you can use the `asConst` util, which simply returns the schema while narrowing its inferred type.\n\n```typescript\nimport { asConst } from \"json-schema-to-ts\";\n\nconst dogSchema = asConst({\n  type: \"object\",\n  ...\n});\n\ntype Dog = FromSchema\u003ctypeof dogSchema\u003e;\n// =\u003e Will work as well 🙌\n```\n\nSince TS 4.9, you can also use the `satisfies` operator to benefit from type-checking and autocompletion:\n\n```typescript\nimport type { JSONSchema } from \"json-schema-to-ts\";\n\nconst dogSchema = {\n  // Type-checked and autocompleted 🙌\n  type: \"object\"\n  ...\n} as const satisfies JSONSchema\n\ntype Dog = FromSchema\u003ctypeof dogSchema\u003e\n// =\u003e Still work 🙌\n```\n\nYou can also use this with JSDocs by wrapping your schema in `/** @type {const} @satisfies {import('json-schema-to-ts').JSONSchema} */ (...)` like:\n\n```\nconst dogSchema = /** @type {const} @satisfies {import('json-schema-to-ts').JSONSchema} */ ({\n  // Type-checked and autocompleted 🙌\n  type: \"object\"\n  ...\n})\n\n/** @type {import('json-schema-to-ts').FromSchema\u003ctypeof dogSchema\u003e} */\nconst dog = { ... }\n```\n\n## Why use `json-schema-to-ts`?\n\nIf you're looking for runtime validation with added types, libraries like [yup](https://github.com/jquense/yup), [zod](https://github.com/vriad/zod) or [runtypes](https://github.com/pelotom/runtypes) may suit your needs while being easier to use!\n\nOn the other hand, JSON schemas have the benefit of being widely used, more versatile and reusable (swaggers, APIaaS...).\n\nIf you prefer to stick to them and can define your schemas in TS instead of JSON (importing JSONs `as const` is not available yet), then `json-schema-to-ts` is made for you:\n\n- ✅ **Schema validation** `FromSchema` raises TS errors on invalid schemas, based on [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/json-schema)'s definitions\n- ✨ **No impact on compiled code**: `json-schema-to-ts` only operates in type space. And after all, what's lighter than a dev-dependency?\n- 🍸 **DRYness**: Less code means less embarrassing typos\n- 🤝 **Real-time consistency**: See that `string` that you used instead of an `enum`? Or this `additionalProperties` you confused with `additionalItems`? Or forgot entirely? Well, `json-schema-to-ts` does!\n- 🔧 **Reliability**: `FromSchema` is extensively tested against [AJV](https://github.com/ajv-validator/ajv), and covers all the use cases that can be handled by TS for now\\*\n- 🏋️‍♂️ **Help on complex schemas**: Get complex schemas right first time with instantaneous typing feedbacks! For instance, it's not obvious the following schema can never be validated:\n\n```typescript\nconst addressSchema = {\n  type: \"object\",\n  allOf: [\n    {\n      properties: {\n        street: { type: \"string\" },\n        city: { type: \"string\" },\n        state: { type: \"string\" },\n      },\n      required: [\"street\", \"city\", \"state\"],\n    },\n    {\n      properties: {\n        type: { enum: [\"residential\", \"business\"] },\n      },\n    },\n  ],\n  additionalProperties: false,\n} as const;\n```\n\nBut it is with `FromSchema`!\n\n```typescript\ntype Address = FromSchema\u003ctypeof addressSchema\u003e;\n// =\u003e never 🙌\n```\n\n\u003e \\*If `json-schema-to-ts` misses one of your use case, feel free to [open an issue](https://github.com/ThomasAribart/json-schema-to-ts/issues) 🤗\n\n## Table of content\n\n- [Installation](#installation)\n- [Use cases](#use-cases)\n  - [Const](#const)\n  - [Enums](#enums)\n  - [Primitive types](#primitive-types)\n  - [Nullable](#nullable)\n  - [Arrays](#arrays)\n  - [Tuples](#tuples)\n  - [Objects](#objects)\n- [Combining schemas](#combining-schemas)\n  - [AnyOf](#anyof)\n  - [AllOf](#allof)\n  - [OneOf](#oneof)\n  - [Not](#not)\n  - [If/Then/Else](#ifthenelse)\n  - [Definitions](#definitions)\n  - [References](#references)\n- [Deserialization](#deserialization)\n- [Extensions](#extensions)\n- [Typeguards](#typeguards)\n  - [Validators](#validators)\n  - [Compilers](#compilers)\n- [FAQ](#frequently-asked-questions)\n\n## Installation\n\n```bash\n# npm\nnpm install --save-dev json-schema-to-ts\n\n# yarn\nyarn add --dev json-schema-to-ts\n```\n\n\u003e `json-schema-to-ts` requires TypeScript 4.3+. Using `strict` mode is required, as well as (apparently) turning off [`noStrictGenericChecks`](https://www.typescriptlang.org/tsconfig#noStrictGenericChecks).\n\n## Use cases\n\n### Const\n\n```typescript\nconst fooSchema = {\n  const: \"foo\",\n} as const;\n\ntype Foo = FromSchema\u003ctypeof fooSchema\u003e;\n// =\u003e \"foo\"\n```\n\n### Enums\n\n```typescript\nconst enumSchema = {\n  enum: [true, 42, { foo: \"bar\" }],\n} as const;\n\ntype Enum = FromSchema\u003ctypeof enumSchema\u003e;\n// =\u003e true | 42 | { foo: \"bar\"}\n```\n\nYou can also go full circle with typescript `enums`.\n\n```typescript\nenum Food {\n  Pizza = \"pizza\",\n  Taco = \"taco\",\n  Fries = \"fries\",\n}\n\nconst enumSchema = {\n  enum: Object.values(Food),\n} as const;\n\ntype Enum = FromSchema\u003ctypeof enumSchema\u003e;\n// =\u003e Food\n```\n\n### Primitive types\n\n```typescript\nconst primitiveTypeSchema = {\n  type: \"null\", // \"boolean\", \"string\", \"integer\", \"number\"\n} as const;\n\ntype PrimitiveType = FromSchema\u003ctypeof primitiveTypeSchema\u003e;\n// =\u003e null, boolean, string or number\n```\n\n```typescript\nconst primitiveTypesSchema = {\n  type: [\"null\", \"string\"],\n} as const;\n\ntype PrimitiveTypes = FromSchema\u003ctypeof primitiveTypesSchema\u003e;\n// =\u003e null | string\n```\n\n\u003e For more complex types, refinment keywords like `required` or `additionalItems` will apply 🙌\n\n### Nullable\n\n```typescript\nconst nullableSchema = {\n  type: \"string\",\n  nullable: true,\n} as const;\n\ntype Nullable = FromSchema\u003ctypeof nullableSchema\u003e;\n// =\u003e string | null\n```\n\n### Arrays\n\n```typescript\nconst arraySchema = {\n  type: \"array\",\n  items: { type: \"string\" },\n} as const;\n\ntype Array = FromSchema\u003ctypeof arraySchema\u003e;\n// =\u003e string[]\n```\n\n### Tuples\n\n```typescript\nconst tupleSchema = {\n  type: \"array\",\n  items: [{ type: \"boolean\" }, { type: \"string\" }],\n} as const;\n\ntype Tuple = FromSchema\u003ctypeof tupleSchema\u003e;\n// =\u003e [] | [boolean] | [boolean, string] | [boolean, string, ...unknown[]]\n```\n\n`FromSchema` supports the `additionalItems` keyword:\n\n```typescript\nconst tupleSchema = {\n  type: \"array\",\n  items: [{ type: \"boolean\" }, { type: \"string\" }],\n  additionalItems: false,\n} as const;\n\ntype Tuple = FromSchema\u003ctypeof tupleSchema\u003e;\n// =\u003e [] | [boolean] | [boolean, string]\n```\n\n```typescript\nconst tupleSchema = {\n  type: \"array\",\n  items: [{ type: \"boolean\" }, { type: \"string\" }],\n  additionalItems: { type: \"number\" },\n} as const;\n\ntype Tuple = FromSchema\u003ctypeof tupleSchema\u003e;\n// =\u003e [] | [boolean] | [boolean, string] | [boolean, string, ...number[]]\n```\n\n...as well as the `minItems` and `maxItems` keywords:\n\n```typescript\nconst tupleSchema = {\n  type: \"array\",\n  items: [{ type: \"boolean\" }, { type: \"string\" }],\n  minItems: 1,\n  maxItems: 2,\n} as const;\n\ntype Tuple = FromSchema\u003ctypeof tupleSchema\u003e;\n// =\u003e [boolean] | [boolean, string]\n```\n\n\u003e Additional items will only work if Typescript's `strictNullChecks` option is activated\n\n### Objects\n\n```typescript\nconst objectSchema = {\n  type: \"object\",\n  properties: {\n    foo: { type: \"string\" },\n    bar: { type: \"number\" },\n  },\n  required: [\"foo\"],\n} as const;\n\ntype Object = FromSchema\u003ctypeof objectSchema\u003e;\n// =\u003e { [x: string]: unknown; foo: string; bar?: number; }\n```\n\nDefaulted properties (even optional ones) will be set as required in the resulting type. You can turn off this behavior by setting the `keepDefaultedPropertiesOptional` option to `true`:\n\n```typescript\nconst defaultedProp = {\n  type: \"object\",\n  properties: {\n    foo: { type: \"string\", default: \"bar\" },\n  },\n  additionalProperties: false,\n} as const;\n\ntype Object = FromSchema\u003ctypeof defaultedProp\u003e;\n// =\u003e { foo: string; }\n\ntype Object = FromSchema\u003c\n  typeof defaultedProp,\n  { keepDefaultedPropertiesOptional: true }\n\u003e;\n// =\u003e { foo?: string; }\n```\n\n`FromSchema` partially supports the `additionalProperties`, `patternProperties` and `unevaluatedProperties` keywords:\n\n- `additionalProperties` and `unevaluatedProperties` can be used to deny additional properties.\n\n```typescript\nconst closedObjectSchema = {\n  ...objectSchema,\n  additionalProperties: false,\n} as const;\n\ntype Object = FromSchema\u003ctypeof closedObjectSchema\u003e;\n// =\u003e { foo: string; bar?: number; }\n```\n\n```typescript\nconst closedObjectSchema = {\n  type: \"object\",\n  allOf: [\n    {\n      properties: {\n        foo: { type: \"string\" },\n      },\n      required: [\"foo\"],\n    },\n    {\n      properties: {\n        bar: { type: \"number\" },\n      },\n    },\n  ],\n  unevaluatedProperties: false,\n} as const;\n\ntype Object = FromSchema\u003ctypeof closedObjectSchema\u003e;\n// =\u003e { foo: string; bar?: number; }\n```\n\n- Used on their own, `additionalProperties` and/or `patternProperties` can be used to type unnamed properties.\n\n```typescript\nconst openObjectSchema = {\n  type: \"object\",\n  additionalProperties: {\n    type: \"boolean\",\n  },\n  patternProperties: {\n    \"^S\": { type: \"string\" },\n    \"^I\": { type: \"integer\" },\n  },\n} as const;\n\ntype Object = FromSchema\u003ctypeof openObjectSchema\u003e;\n// =\u003e { [x: string]: string | number | boolean }\n```\n\nHowever:\n\n- When used in combination with the `properties` keyword, extra properties will always be typed as `unknown` to avoid conflicts.\n\n```typescript\nconst mixedObjectSchema = {\n  type: \"object\",\n  properties: {\n    foo: { enum: [\"bar\", \"baz\"] },\n  },\n  additionalProperties: { type: \"string\" },\n} as const;\n\ntype Object = FromSchema\u003ctypeof mixedObjectSchema\u003e;\n// =\u003e { [x: string]: unknown; foo?: \"bar\" | \"baz\"; }\n```\n\n- Due to its context-dependent nature, `unevaluatedProperties` does not type extra-properties when used on its own. Use `additionalProperties` instead.\n\n```typescript\nconst openObjectSchema = {\n  type: \"object\",\n  unevaluatedProperties: {\n    type: \"boolean\",\n  },\n} as const;\n\ntype Object = FromSchema\u003ctypeof openObjectSchema\u003e;\n// =\u003e { [x: string]: unknown }\n```\n\n## Combining schemas\n\n### AnyOf\n\n```typescript\nconst anyOfSchema = {\n  anyOf: [\n    { type: \"string\" },\n    {\n      type: \"array\",\n      items: { type: \"string\" },\n    },\n  ],\n} as const;\n\ntype AnyOf = FromSchema\u003ctypeof anyOfSchema\u003e;\n// =\u003e string | string[]\n```\n\n`FromSchema` will correctly infer factored schemas:\n\n```typescript\nconst factoredSchema = {\n  type: \"object\",\n  properties: {\n    bool: { type: \"boolean\" },\n  },\n  required: [\"bool\"],\n  anyOf: [\n    {\n      properties: {\n        str: { type: \"string\" },\n      },\n      required: [\"str\"],\n    },\n    {\n      properties: {\n        num: { type: \"number\" },\n      },\n    },\n  ],\n} as const;\n\ntype Factored = FromSchema\u003ctypeof factoredSchema\u003e;\n// =\u003e {\n//  [x:string]: unknown;\n//  bool: boolean;\n//  str: string;\n// } | {\n//  [x:string]: unknown;\n//  bool: boolean;\n//  num?: number;\n// }\n```\n\n### OneOf\n\n`FromSchema` will parse the `oneOf` keyword in the same way as `anyOf`:\n\n```typescript\nconst catSchema = {\n  type: \"object\",\n  oneOf: [\n    {\n      properties: {\n        name: { type: \"string\" },\n      },\n      required: [\"name\"],\n    },\n    {\n      properties: {\n        color: { enum: [\"black\", \"brown\", \"white\"] },\n      },\n    },\n  ],\n} as const;\n\ntype Cat = FromSchema\u003ctypeof catSchema\u003e;\n// =\u003e {\n//  [x: string]: unknown;\n//  name: string;\n// } | {\n//  [x: string]: unknown;\n//  color?: \"black\" | \"brown\" | \"white\";\n// }\n\n// =\u003e Error will NOT be raised 😱\nconst invalidCat: Cat = { name: \"Garfield\" };\n```\n\n### AllOf\n\n```typescript\nconst addressSchema = {\n  type: \"object\",\n  allOf: [\n    {\n      properties: {\n        address: { type: \"string\" },\n        city: { type: \"string\" },\n        state: { type: \"string\" },\n      },\n      required: [\"address\", \"city\", \"state\"],\n    },\n    {\n      properties: {\n        type: { enum: [\"residential\", \"business\"] },\n      },\n    },\n  ],\n} as const;\n\ntype Address = FromSchema\u003ctypeof addressSchema\u003e;\n// =\u003e {\n//   [x: string]: unknown;\n//   address: string;\n//   city: string;\n//   state: string;\n//   type?: \"residential\" | \"business\";\n// }\n```\n\n### Not\n\nExclusions require heavy computations, that can sometimes be aborted by Typescript and end up in `any` inferred types. For this reason, they are not activated by default: You can opt-in with the `parseNotKeyword` option.\n\n```typescript\nconst tupleSchema = {\n  type: \"array\",\n  items: [{ const: 1 }, { const: 2 }],\n  additionalItems: false,\n  not: {\n    const: [1],\n  },\n} as const;\n\ntype Tuple = FromSchema\u003ctypeof tupleSchema, { parseNotKeyword: true }\u003e;\n// =\u003e [] | [1, 2]\n```\n\n```typescript\nconst primitiveTypeSchema = {\n  not: {\n    type: [\"array\", \"object\"],\n  },\n} as const;\n\ntype PrimitiveType = FromSchema\u003c\n  typeof primitiveTypeSchema,\n  { parseNotKeyword: true }\n\u003e;\n// =\u003e null | boolean | number | string\n```\n\nIn objects and tuples, the exclusion will propagate to properties/items if it can collapse on a single one.\n\n```typescript\n// 👍 Can be propagated on \"animal\" property\nconst petSchema = {\n  type: \"object\",\n  properties: {\n    animal: { enum: [\"cat\", \"dog\", \"boat\"] },\n  },\n  not: {\n    properties: { animal: { const: \"boat\" } },\n  },\n  required: [\"animal\"],\n  additionalProperties: false,\n} as const;\n\ntype Pet = FromSchema\u003ctypeof petSchema, { parseNotKeyword: true }\u003e;\n// =\u003e { animal: \"cat\" | \"dog\" }\n```\n\n```typescript\n// ❌ Cannot be propagated\nconst petSchema = {\n  type: \"object\",\n  properties: {\n    animal: { enum: [\"cat\", \"dog\"] },\n    color: { enum: [\"black\", \"brown\", \"white\"] },\n  },\n  not: {\n    const: { animal: \"cat\", color: \"white\" },\n  },\n  required: [\"animal\", \"color\"],\n  additionalProperties: false,\n} as const;\n\ntype Pet = FromSchema\u003ctypeof petSchema, { parseNotKeyword: true }\u003e;\n// =\u003e { animal: \"cat\" | \"dog\", color: \"black\" | \"brown\" | \"white\" }\n```\n\nAs some actionable keywords are not yet parsed, exclusions that resolve to `never` are granted the benefit of the doubt and omitted. For the moment, `FromSchema` assumes that you are not crafting unvalidatable exclusions.\n\n```typescript\nconst oddNumberSchema = {\n  type: \"number\",\n  not: { multipleOf: 2 },\n} as const;\n\ntype OddNumber = FromSchema\u003ctypeof oddNumberSchema, { parseNotKeyword: true }\u003e;\n// =\u003e should and will resolve to \"number\"\n\nconst incorrectSchema = {\n  type: \"number\",\n  not: { bogus: \"option\" },\n} as const;\n\ntype Incorrect = FromSchema\u003ctypeof incorrectSchema, { parseNotKeyword: true }\u003e;\n// =\u003e should resolve to \"never\" but will still resolve to \"number\"\n```\n\nAlso, keep in mind that TypeScript misses [refinment types](https://en.wikipedia.org/wiki/Refinement_type):\n\n```typescript\nconst goodLanguageSchema = {\n  type: \"string\",\n  not: {\n    enum: [\"Bummer\", \"Silly\", \"Lazy sod !\"],\n  },\n} as const;\n\ntype GoodLanguage = FromSchema\u003c\n  typeof goodLanguageSchema,\n  { parseNotKeyword: true }\n\u003e;\n// =\u003e string\n```\n\n### If/Then/Else\n\nFor the same reason as the `Not` keyword, conditions parsing is not activated by default: You can opt-in with the `parseIfThenElseKeywords` option.\n\n```typescript\nconst petSchema = {\n  type: \"object\",\n  properties: {\n    animal: { enum: [\"cat\", \"dog\"] },\n    dogBreed: { enum: Object.values(DogBreed) },\n    catBreed: { enum: Object.values(CatBreed) },\n  },\n  required: [\"animal\"],\n  if: {\n    properties: {\n      animal: { const: \"dog\" },\n    },\n  },\n  then: {\n    required: [\"dogBreed\"],\n    not: { required: [\"catBreed\"] },\n  },\n  else: {\n    required: [\"catBreed\"],\n    not: { required: [\"dogBreed\"] },\n  },\n  additionalProperties: false,\n} as const;\n\ntype Pet = FromSchema\u003ctypeof petSchema, { parseIfThenElseKeywords: true }\u003e;\n// =\u003e {\n//  animal: \"dog\";\n//  dogBreed: DogBreed;\n//  catBreed?: CatBreed | undefined\n// } | {\n//  animal: \"cat\";\n//  catBreed: CatBreed;\n//  dogBreed?: DogBreed | undefined\n// }\n```\n\n\u003e ☝️ `FromSchema` computes the resulting type as `(If ∩ Then) ∪ (¬If ∩ Else)`. While correct in theory, remember that the `not` keyword is not perfectly assimilated, which may become an issue in some complex schemas.\n\n### Definitions\n\n```typescript\nconst userSchema = {\n  type: \"object\",\n  properties: {\n    name: { $ref: \"#/definitions/name\" },\n    age: { $ref: \"#/definitions/age\" },\n  },\n  required: [\"name\", \"age\"],\n  additionalProperties: false,\n  definitions: {\n    name: { type: \"string\" },\n    age: { type: \"integer\" },\n  },\n} as const;\n\ntype User = FromSchema\u003ctypeof userSchema\u003e;\n// =\u003e {\n//  name: string;\n//  age: number;\n// }\n```\n\n\u003e ☝️ Wether in definitions or references, `FromSchema` will not work on recursive schemas for now.\n\n### References\n\nUnlike run-time validator classes like [AJV](https://github.com/ajv-validator/ajv), TS types cannot withhold internal states. Thus, they cannot keep any identified schemas in memory.\n\nBut you can hydrate them via the `references` option:\n\n```typescript\nconst userSchema = {\n  $id: \"http://example.com/schemas/user.json\",\n  type: \"object\",\n  properties: {\n    name: { type: \"string\" },\n    age: { type: \"integer\" },\n  },\n  required: [\"name\", \"age\"],\n  additionalProperties: false,\n} as const;\n\nconst usersSchema = {\n  type: \"array\",\n  items: {\n    $ref: \"http://example.com/schemas/user.json\",\n  },\n} as const;\n\ntype Users = FromSchema\u003c\n  typeof usersSchema,\n  { references: [typeof userSchema] }\n\u003e;\n// =\u003e {\n//  name: string;\n//  age: string;\n// }[]\n\nconst anotherUsersSchema = {\n  $id: \"http://example.com/schemas/users.json\",\n  type: \"array\",\n  items: { $ref: \"user.json\" },\n} as const;\n// =\u003e Will work as well 🙌\n```\n\n## Deserialization\n\nYou can specify deserialization patterns with the `deserialize` option:\n\n```typescript\nconst userSchema = {\n  type: \"object\",\n  properties: {\n    name: { type: \"string\" },\n    email: {\n      type: \"string\",\n      format: \"email\",\n    },\n    birthDate: {\n      type: \"string\",\n      format: \"date-time\",\n    },\n  },\n  required: [\"name\", \"email\", \"birthDate\"],\n  additionalProperties: false,\n} as const;\n\ntype Email = string \u0026 { brand: \"email\" };\n\ntype User = FromSchema\u003c\n  typeof userSchema,\n  {\n    deserialize: [\n      {\n        pattern: {\n          type: \"string\";\n          format: \"email\";\n        };\n        output: Email;\n      },\n      {\n        pattern: {\n          type: \"string\";\n          format: \"date-time\";\n        };\n        output: Date;\n      },\n    ];\n  }\n\u003e;\n// =\u003e {\n//  name: string;\n//  email: Email;\n//  birthDate: Date;\n// }\n```\n\n## Extensions\n\nIf you need to extend the JSON Schema spec with custom properties, use the `ExtendedJSONSchema` and `FromExtendedSchema` types to benefit from `json-schema-to-ts`:\n\n```typescript\nimport type { ExtendedJSONSchema, FromExtendedSchema } from \"json-schema-to-ts\";\n\ntype CustomProps = {\n  numberType: \"int\" | \"float\" | \"bigInt\";\n};\n\nconst bigIntSchema = {\n  type: \"number\",\n  numberType: \"bigInt\",\n  // 👇 Ensures mySchema is correct (includes extension)\n} as const satisfies ExtendedJSONSchema\u003cCustomProps\u003e;\n\ntype BigInt = FromExtendedSchema\u003c\n  CustomProps,\n  typeof bigIntSchema,\n  {\n    // 👇 Works very well with the deserialize option!\n    deserialize: [\n      {\n        pattern: {\n          type: \"number\";\n          numberType: \"bigInt\";\n        };\n        output: bigint;\n      },\n    ];\n  }\n\u003e;\n```\n\n## Typeguards\n\nYou can use `FromSchema` to implement your own typeguard:\n\n```typescript\nimport { FromSchema, Validator } from \"json-schema-to-ts\";\n\n// It's important to:\n// - Explicitely type your validator as Validator\n// - Use FromSchema as the default value of a 2nd generic first\nconst validate: Validator = \u003cS extends JSONSchema, T = FromSchema\u003cS\u003e\u003e(\n  schema: S,\n  data: unknown\n): data is T =\u003e {\n  const isDataValid: boolean = ... // Implement validation here\n  return isDataValid;\n};\n\nconst petSchema = { ... } as const\nlet data: unknown;\nif (validate(petSchema, data)) {\n  const { name, ... } = data; // data is typed as Pet 🙌\n}\n```\n\nIf needed, you can provide `FromSchema` options and additional validation options to the `Validator` type:\n\n```typescript\ntype FromSchemaOptions = { parseNotKeyword: true };\ntype ValidationOptions = [{ fastValidate: boolean }]\n\nconst validate: Validator\u003cFromSchemaOptions, ValidationOptions\u003e = \u003c\n  S extends JSONSchema,\n  T = FromSchema\u003cS, FromSchemaOptions\u003e\n\u003e(\n  schema: S,\n  data: unknown,\n  ...validationOptions: ValidationOptions\n): data is T =\u003e { ... };\n```\n\n`json-schema-to-ts` also exposes two helpers to write type guards. They don't impact the code that you wrote (they simply `return` it), but turn it into type guards.\n\nYou can use them to wrap either [`validators`](#validator) or [`compilers`](#compiler).\n\n### Validators\n\nA validator is a function that receives a schema plus some data, and returns `true` if the data is valid compared to the schema, `false` otherwise.\n\nYou can use the `wrapValidatorAsTypeGuard` helper to turn validators into type guards. Here is an implementation with [ajv](https://ajv.js.org/):\n\n```typescript\nimport Ajv from \"ajv\";\nimport { $Validator, wrapValidatorAsTypeGuard } from \"json-schema-to-ts\";\n\nconst ajv = new Ajv();\n\n// The initial validator definition is up to you\n// ($Validator is prefixed with $ to differ from resulting type guard)\nconst $validate: $Validator = (schema, data) =\u003e ajv.validate(schema, data);\n\nconst validate = wrapValidatorAsTypeGuard($validate);\n\nconst petSchema = { ... } as const;\n\nlet data: unknown;\nif (validate(petSchema, data)) {\n  const { name, ... } = data; // data is typed as Pet 🙌\n}\n```\n\nIf needed, you can provide `FromSchema` options and additional validation options as generic types:\n\n```typescript\ntype FromSchemaOptions = { parseNotKeyword: true };\ntype ValidationOptions = [{ fastValidate: boolean }]\n\nconst $validate: $Validator\u003cValidationOptions\u003e = (\n  schema,\n  data,\n  ...validationOptions // typed as ValidationOptions\n) =\u003e { ... };\n\n// validate will inherit from ValidationOptions\nconst validate = wrapValidatorAsTypeGuard($validate);\n\n// with special FromSchemaOptions\n// (ValidationOptions needs to be re-provided)\nconst validate = wrapValidatorAsTypeGuard\u003c\n  FromSchemaOptions,\n  ValidationOptions\n\u003e($validate);\n```\n\n### Compilers\n\nA compiler is a function that takes a schema as an input and returns a data validator for this schema as an output.\n\nYou can use the `wrapCompilerAsTypeGuard` helper to turn compilers into type guard builders. Here is an implementation with [ajv](https://ajv.js.org/):\n\n```typescript\nimport Ajv from \"ajv\";\nimport { $Compiler, wrapCompilerAsTypeGuard } from \"json-schema-to-ts\";\n\n// The initial compiler definition is up to you\n// ($Compiler is prefixed with $ to differ from resulting type guard)\nconst $compile: $Compiler = (schema) =\u003e ajv.compile(schema);\n\nconst compile = wrapCompilerAsTypeGuard($compile);\n\nconst petSchema = { ... } as const;\n\nconst isPet = compile(petSchema);\n\nlet data: unknown;\nif (isPet(data)) {\n  const { name, ... } = data; // data is typed as Pet 🙌\n}\n```\n\nIf needed, you can provide `FromSchema` options, additional compiling and validation options as generic types:\n\n```typescript\ntype FromSchemaOptions = { parseNotKeyword: true };\ntype CompilingOptions = [{ fastCompile: boolean }];\ntype ValidationOptions = [{ fastValidate: boolean }];\n\nconst $compile: $Compiler\u003cCompilingOptions, ValidationOptions\u003e = (\n  schema,\n  ...compilingOptions // typed as CompilingOptions\n) =\u003e {\n  ...\n\n  return (\n    data,\n    ...validationOptions // typed as ValidationOptions\n  ) =\u003e { ...  };\n};\n\n// compile will inherit from all options\nconst compile = wrapCompilerAsTypeGuard($compile);\n\n// with special FromSchemaOptions\n// (options need to be re-provided)\nconst compile = wrapCompilerAsTypeGuard\u003c\n  FromSchemaOptions,\n  CompilingOptions,\n  ValidationOptions\n\u003e($compile);\n```\n\n## Frequently Asked Questions\n\n- [Does `json-schema-to-ts` work on _.json_ file schemas?](./documentation/FAQs/does-json-schema-to-ts-work-on-json-file-schemas.md)\n- [Will `json-schema-to-ts` impact the performances of my IDE/compiler?](./documentation/FAQs/will-json-schema-to-ts-impact-the-performances-of-my-ide-compiler.md)\n- [How can I apply `FromSchema` on generics?](./documentation/FAQs/applying-from-schema-on-generics.md)\n- [I get a `type instantiation is excessively deep and potentially infinite` error, what should I do?](./documentation/FAQs/i-get-a-type-instantiation-is-excessively-deep-and-potentially-infinite-error-what-should-i-do.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasaribart%2Fjson-schema-to-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomasaribart%2Fjson-schema-to-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasaribart%2Fjson-schema-to-ts/lists"}