{"id":16720399,"url":"https://github.com/tomokimiyauci/typestruct","last_synced_at":"2026-06-01T03:31:27.275Z","repository":{"id":57766030,"uuid":"526832358","full_name":"TomokiMiyauci/typestruct","owner":"TomokiMiyauci","description":"Composable and checkable JavaScript (and TypeScript) data structure","archived":false,"fork":false,"pushed_at":"2022-11-06T11:27:16.000Z","size":374,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-23T14:02:22.167Z","etag":null,"topics":["assert","assertion","check","checker","error","is","schema","struct","structure","types","typescript","valid","validate","validation","validator"],"latest_commit_sha":null,"homepage":"https://doc.deno.land/https/deno.land/x/typestruct/mod.ts","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/TomokiMiyauci.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-20T05:15:47.000Z","updated_at":"2022-10-26T14:15:57.000Z","dependencies_parsed_at":"2023-01-21T23:17:02.849Z","dependency_job_id":null,"html_url":"https://github.com/TomokiMiyauci/typestruct","commit_stats":null,"previous_names":["schemaland/schema.js"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/TomokiMiyauci/typestruct","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Ftypestruct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Ftypestruct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Ftypestruct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Ftypestruct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TomokiMiyauci","download_url":"https://codeload.github.com/TomokiMiyauci/typestruct/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomokiMiyauci%2Ftypestruct/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27670272,"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","status":"online","status_checked_at":"2025-12-11T02:00:11.302Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["assert","assertion","check","checker","error","is","schema","struct","structure","types","typescript","valid","validate","validation","validator"],"created_at":"2024-10-12T22:07:00.148Z","updated_at":"2025-12-11T21:10:18.269Z","avatar_url":"https://github.com/TomokiMiyauci.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# schema.js\n\n\u003cimg alt=\"logo icon\" src=\"./_medias/logo.png\" width=\"180px\" height=\"180px\"\u003e\n\nUniversal, tiny schema for JavaScript data types.\n\n[![deno land](http://img.shields.io/badge/available%20on-deno.land/x-lightgrey.svg?logo=deno)](https://deno.land/x/schema_js)\n[![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/schema_js/mod.ts)\n[![codecov](https://codecov.io/gh/schemaland/schema.js/branch/beta/graph/badge.svg?token=nHsoT44zg6)](https://codecov.io/gh/schemaland/schema.js)\n\n\u003c/div\u003e\n\n## Design\n\nFor this project, we will define the schema based on JavaScript data types.\n\nJavaScript can be classified into two data types called primitives and objects.\n\nIf we further classify them according to whether they are Unit type or\nCollective types, they can be classified into 8 data types.\n\nUnit type is a type that has only a single value. Collection type is set of Unit\ntype.\n\n|           | Unit type   | Collective type                                   |\n| --------- | ----------- | ------------------------------------------------- |\n| Primitive | `undefined` | `string`, `number`, `bigint`, `boolean`, `symbol` |\n| Object    | `null`      | `object`                                          |\n\nA subtype of `object`, `Function` is a special type that JavaScript treats as\nfirst class.\n\nSo for this project, we define `Function` as a supertype in addition to the 8\ntypes above.\n\n## Core schema\n\nCreate JavaScript primitive data schema.\n\n```ts\nimport {\n  BigintSchema,\n  BooleanSchema,\n  NumberSchema,\n  StringSchema,\n  SymbolSchema,\n  UndefinedSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst stringSchema = new StringSchema();\nconst numberSchema = new NumberSchema();\nconst bigintSchema = new BigintSchema();\nconst booleanSchema = new BooleanSchema();\nconst undefinedSchema = new UndefinedSchema();\nconst symbolSchema = new SymbolSchema();\n```\n\nCreate JavaScript objective data schema.\n\n```ts\nimport {\n  FunctionSchema,\n  NullSchema,\n  ObjectSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst objectSchema = new ObjectSchema();\nconst functionSchema = new FunctionSchema();\nconst nullSchema = new NullSchema();\n```\n\n## Assert with schema\n\nAssert whether the value satisfies the schema.\n\n```ts\nimport {\n  assertSchema,\n  BooleanSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst value: unknown = true;\nassertSchema(new BooleanSchema(), value);\n// value is `boolean`\nassertSchema(new BooleanSchema(true), value);\n// value is `true`\nassertSchema(new BooleanSchema(false), value); // throws SchemaError\n```\n\n## Validate with schema\n\nIf you do not want to throw an error, you can use the `validateSchema` function.\n\n```ts\nimport {\n  ObjectSchema,\n  StringSchema,\n  validateSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst schema = new ObjectSchema({\n  name: new StringSchema(),\n  type: new StringSchema(\"dog\"),\n});\n\nconst result = validateSchema(schema, {});\nif (result.pass) {\n  result.data; // { name: string, type: \"dog\" }\n} else {\n  result.errors; // SchemaError[]\n}\n```\n\n## Additional subtype assertion (narrowing)\n\nFor the Collective type, you can add assertions of subtypes.\n\nThe Collective type has the `and` method. It accept subtype schema and returns a\nnew Collective type. The new Collective type will be type narrowed by the\nsubtype schema.\n\nExample of creating a tuple (`[0, \"hi\"]`) schema from an object schema:\n\n```ts\nimport {\n  ArraySchema,\n  assertSchema,\n  NumberSchema,\n  ObjectSchema,\n  SchemaError,\n  StringSchema,\n  TupleSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst value: unknown = undefined;\n\nconst tupleSchema = new ObjectSchema().and(new ArraySchema()).and(\n  new TupleSchema(\n    new NumberSchema(0),\n    new StringSchema(\"hi\"),\n  ),\n);\nassertSchema(tupleSchema, value);\n// value is `[0, \"hi\"]`\n```\n\n## Logical operation schema\n\nProvides the logical operations of the schema. Several schemas can be multiplied\ntogether to create a new schema.\n\n### Logical OR\n\nThe logical OR schema (logical disjunction) for a set of schemas is true if and\nonly if one or more of its schemas is true.\n\nType inference works correctly.\n\n```ts\nimport {\n  assertSchema,\n  NullSchema,\n  NumberSchema,\n  OrSchema,\n  StringSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst schema = new OrSchema(\n  new StringSchema(),\n  new NumberSchema(),\n  new NullSchema(),\n);\nconst value: unknown = undefined;\nassertSchema(schema, value);\n// value is `string` | `number` | null\n```\n\n### Logical AND\n\nThe logical AND schema (logical conjunction) for a set of schemas will be true\nif and only if all the schemas are true. Otherwise it will be false.\n\nType inference works correctly.\n\n```ts\nimport {\n  AndSchema,\n  assertSchema,\n  OrSchema,\n  StringSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst schema = new AndSchema(\n  new StringSchema(\"hello\"),\n  new StringSchema(),\n);\nconst value: unknown = undefined;\nassertSchema(schema, value);\n// value is `\"hello\"`\n```\n\n### Logical NOT\n\nThe logical NOT schema (logical complement, negation) takes valid schema to\ninvalid and vice versa.\n\nType inference works correctly.\n\n```ts\nimport {\n  assertSchema,\n  BooleanSchema,\n  NotSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst value: unknown = undefined;\nassertSchema(new NotSchema(new BooleanSchema()), value);\n// value is `string` | `number` | ...\nassertSchema(new NotSchema(new BooleanSchema(true)), value);\n// value is `false` | `string` | `number` | ...\n```\n\n## String subtype schema\n\nProvides schema for string subtypes.\n\n```ts\nimport {\n  assertSchema,\n  LengthSchema,\n  MaxLengthSchema,\n  MinLengthSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst maxLengthSchema = new MaxLengthSchema(255);\nconst minLengthSchema = new MinLengthSchema(10);\nconst lengthSchema = new LengthSchema(20);\n\nconst value: string = \"This is string subtype type.\";\nassertSchema(maxLengthSchema, value);\nassertSchema(minLengthSchema, value);\nassertSchema(lengthSchema, value); // throw SchemaError\n```\n\n### Email schema\n\nSchema of `string` subtype of email format.\n\n```ts\nimport {\n  assertSchema,\n  MaxLengthSchema,\n  StringEmailSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst emailFormatAndLessThan20 = new StringEmailSchema().and(\n  new MaxLengthSchema(20),\n);\nassertSchema(emailFormatAndLessThan20, \"contact@test.test\");\n```\n\n## Partial schema\n\nSchema of optional properties.\n\n```ts\nimport {\n  assertSchema,\n  FunctionSchema,\n  PartialSchema,\n  StringSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst abilitySchema = new PartialSchema({\n  fly: new FunctionSchema(),\n});\nconst model = { type: \"bird\" } as const;\nassertSchema(abilitySchema, model);\n// { type: \"bird\", fly?: Function }\n```\n\n## Union subtype schema\n\nThe union subtype schema is a schema that can be used for multiple types.\n\n### Max schema\n\ntype \u0026isin; `number` \u0026#x22C3; `bigint`\n\nSchema of max value for `number` or `bigint` subtype.\n\n```ts\nimport {\n  assertSchema,\n  MaxSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport { assertThrows } from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nassertSchema(new MaxSchema(10), 5);\nassertThrows(() =\u003e assertSchema(new MaxSchema(10), 11));\n```\n\n### Min schema\n\ntype ∈ `number` \u0026#x22C3; `bigint`\n\nSchema of min value for `number` or `bigint` subtype.\n\n```ts\nimport {\n  assertSchema,\n  MinSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport { assertThrows } from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nassertSchema(new MinSchema(5), 10);\nassertThrows(() =\u003e assertSchema(new MinSchema(5), 0));\n```\n\n### Count schema\n\ntype ∈ `Iterable\u003cunknown\u003e`\n\nSchema of number of elements for `Iterable` data types.\n\n```ts\nimport {\n  assertSchema,\n  CountSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport {\n  assertEquals,\n  assertThrows,\n} from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nconst schema = new CountSchema(10);\nassertSchema(schema, \"abcdefghij\");\nassertThrows(() =\u003e assertSchema(schema, []));\n```\n\n### Min count schema\n\ntype ∈ `Iterable\u003cunknown\u003e`\n\nSchema of min number of elements for `Iterable` data types.\n\n```ts\nimport {\n  assertSchema,\n  MinCountSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport {\n  assertEquals,\n  assertThrows,\n} from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nconst schema = new MinCountSchema(8);\nassertSchema(schema, \"password\");\nassertThrows(() =\u003e assertSchema(schema, new Array(4)));\n```\n\n### Max count schema\n\ntype ∈ `Iterable\u003cunknown\u003e`\n\nSchema of max number of elements for `Iterable` data types.\n\n```ts\nimport {\n  assertSchema,\n  MaxCountSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport {\n  assertEquals,\n  assertThrows,\n} from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nconst schema = new MaxCountSchema(255);\nassertSchema(schema, \"https://test.com\");\nassertThrows(() =\u003e assertSchema(schema, new Array(1000)));\n```\n\n#### Difference of Length schema\n\n- Length retrieves a value from the `length` property.\n- Count counts the actual number of elements.\n- They differ in the way they count strings.\n\nIn strings, Length schema counts the number of code units. In contrast, Count\nschema counts the number of characters.\n\n```ts\nimport { assertEquals } from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\nassertEquals(\"A\\uD87E\\uDC04Z\".length, 4);\nassertEquals([...\"A\\uD87E\\uDC04Z\"].length, 3);\n```\n\nYou should use the count schema in most cases.\n\n## Built-in Objects schema\n\nThis project provide built-in object schemas.\n\n[All list](./docs/built_in_objects.md)\n\n## Array schema\n\n```ts\nimport {\n  ArraySchema,\n  assertSchema,\n  StringSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst value: unknown = undefined;\nassertSchema(new ArraySchema(), value);\n// value is `{}[]`\nassertSchema(new ArraySchema([new StringSchema()]), value);\n// value is `string[]`\n```\n\n### Tuple schema\n\nIt is a sub-type of the `Array` object and represents an array of a finite\nnumber of elements.\n\n```ts\nimport {\n  ArraySchema,\n  assertSchema,\n  NumberSchema,\n  StringSchema,\n  TupleSchema,\n  UndefinedSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst value: any[] = [];\nconst tupleSchema = new TupleSchema(\n  new NumberSchema(),\n  new StringSchema(\"hello\"),\n  new UndefinedSchema(),\n);\nassertSchema(tupleSchema, value);\n// value is [number, \"hello\", undefined]\n\nconst arraySchema = new ArraySchema().and(tupleSchema);\nconst unknown: unknown = null;\nassertSchema(arraySchema, unknown);\n// value is [number, \"hello\", undefined]\n```\n\n## Date schema\n\nSchema of `Date` object.\n\n```ts\nimport {\n  assertSchema,\n  DateSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\nimport {\n  assertThrows,\n} from \"https://deno.land/std@$VERSION/testing/asserts.ts\";\n\nconst schema = new DateSchema();\nassertSchema(schema, new Date());\nassertThrows(() =\u003e assertSchema(schema, {}));\n```\n\n## Type inference\n\nYou can derive the correct type inference by assertSchema, but you can do the\nsame from TypeScript types.\n\n```ts\nimport {\n  ArraySchema,\n  InferSchema,\n  NumberSchema,\n  ObjectSchema,\n  StringSchema,\n  TupleSchema,\n} from \"https://deno.land/x/schema_js@$VERSION/mod.ts\";\n\nconst schema = new ObjectSchema({\n  a: new StringSchema(),\n  b: new ArraySchema().and(\n    new TupleSchema(new StringSchema(\"hello\"), new NumberSchema()),\n  ),\n  c: new ObjectSchema({\n    d: new NumberSchema(0),\n  }),\n});\n\ntype Schema = InferSchema\u003ctypeof schema\u003e;\ntype EqualTo = {\n  a: string;\n  b: [\"hello\", number];\n  c: { d: 0 };\n};\n```\n\n## API\n\nAll APIs can be found in the\n[deno doc](https://doc.deno.land/https/deno.land/x/schema_js/mod.ts).\n\n## Performance\n\nBenchmark script with comparison to several popular schema library is available.\n\n```bash\ndeno bench --unstable\n```\n\nYou can check the\n[benchmark](https://github.com/schemaland/schema.js/runs/7979671007?check_suite_focus=true#step:4:26).\n\n## License\n\nCopyright © 2022-present [schemaland](https://github.com/schemaland).\n\nReleased under the [MIT](./LICENSE) license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomokimiyauci%2Ftypestruct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomokimiyauci%2Ftypestruct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomokimiyauci%2Ftypestruct/lists"}