{"id":23143392,"url":"https://github.com/xieyuheng/ty","last_synced_at":"2025-10-16T04:56:15.914Z","repository":{"id":49367451,"uuid":"394955639","full_name":"xieyuheng/ty","owner":"xieyuheng","description":"Validate untyped data and return well typed result.","archived":false,"fork":false,"pushed_at":"2024-10-26T11:43:40.000Z","size":468,"stargazers_count":21,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-09T19:34:35.017Z","etag":null,"topics":["javascript","json-schema","schema","typescript","validator","well-typed"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xieyuheng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-11T10:49:41.000Z","updated_at":"2025-10-06T09:50:57.000Z","dependencies_parsed_at":"2024-12-17T15:13:25.486Z","dependency_job_id":"6bc96ab7-d079-4af7-ad0e-8f5086b64bc1","html_url":"https://github.com/xieyuheng/ty","commit_stats":null,"previous_names":[],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/xieyuheng/ty","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyuheng%2Fty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyuheng%2Fty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyuheng%2Fty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyuheng%2Fty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xieyuheng","download_url":"https://codeload.github.com/xieyuheng/ty/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xieyuheng%2Fty/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003486,"owners_count":26083594,"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-10-10T02:00:06.843Z","response_time":62,"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":["javascript","json-schema","schema","typescript","validator","well-typed"],"created_at":"2024-12-17T15:13:21.479Z","updated_at":"2025-10-16T04:56:15.881Z","avatar_url":"https://github.com/xieyuheng.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ty\n\nValidate untyped data and return well typed result.\n\n- This package has no dependencies.\n\n## Install\n\n```bash\nnpm i @xieyuheng/ty\n```\n\n## Examples\n\n### Validation untyped data\n\n```typescript\nimport ty, { Obtain } from \"@xieyuheng/ty\"\n\nconst userSchema = ty.object({\n  id: ty.int({ min: 0 }),\n  first_name: ty.string(),\n  last_name: ty.string(),\n})\n\ntype User = Obtain\u003ctypeof userSchema\u003e\n\n// NOTE We can extract a `User` type from the type of `userSchema`,\n//   which will be the same as the following type definition:\n\n// type User = {\n//   id: number\n//   first_name: string\n//   last_name: string\n// }\n\n{\n  const data: any = {\n    id: 1,\n    first_name: \"Yuheng\",\n    last_name: \"Xie\",\n  }\n\n  const user: User = userSchema.validate(data)\n}\n```\n\n### Recursive and generic schema\n\n```typescript\ntype List\u003cT\u003e = null | { head: T; tail: List\u003cT\u003e }\n\nfunction cons\u003cT\u003e(head: T, tail: List\u003cT\u003e): List\u003cT\u003e {\n  return { head, tail }\n}\n\nfunction listSchema\u003cT\u003e(itemSchema: Schema\u003cT\u003e): Schema\u003cList\u003cT\u003e\u003e {\n  const nullSchema = ty.null()\n  const consSchema = ty.object({\n    head: itemSchema,\n    tail: ty.lazy(() =\u003e listSchema(itemSchema)),\n  })\n  return ty.union(nullSchema, consSchema)\n}\n\n{\n  const schema = listSchema(ty.string())\n  const data0: List\u003cstring\u003e = schema.validate(null)\n  const data1: List\u003cstring\u003e = schema.validate(cons(\"a\", null))\n  const data2: List\u003cstring\u003e = schema.validate(cons(\"a\", cons(\"b\", null)))\n  const data3: List\u003cstring\u003e = schema.validate(\n    cons(\"a\", cons(\"b\", cons(\"c\", null))),\n  )\n  schema.expectInvalid(cons(1, null))\n  schema.expectInvalid(cons(1, cons(2, null)))\n  schema.expectInvalid(cons(1, cons(2, cons(3, null))))\n}\n\n{\n  const schema = listSchema(ty.number())\n  const data0: List\u003cnumber\u003e = schema.validate(null)\n  const data1: List\u003cnumber\u003e = schema.validate(cons(1, null))\n  const data2: List\u003cnumber\u003e = schema.validate(cons(1, cons(2, null)))\n  const data3: List\u003cnumber\u003e = schema.validate(cons(1, cons(2, cons(3, null))))\n  schema.expectInvalid(cons(\"a\", null))\n  schema.expectInvalid(cons(\"a\", cons(\"b\", null)))\n  schema.expectInvalid(cons(\"a\", cons(\"b\", cons(\"c\", null))))\n}\n```\n\n## API Docs\n\n**Primitive:**\n\n- [ty.string()](src/tests/string.test.ts)\n- [ty.url()](src/tests/url.test.ts)\n- [ty.date()](src/tests/date.test.ts)\n- [ty.number()](src/tests/number.test.ts)\n- [ty.int()](src/tests/int.test.ts)\n- [ty.boolean()](src/tests/boolean.test.ts)\n- [ty.null()](src/tests/null.test.ts)\n- [ty.undefined()](src/tests/undefined.test.ts)\n- [ty.any()](src/tests/any.test.ts)\n\n**Collection:**\n\n- [ty.object({ ...schemas })](src/tests/object.test.ts)\n- [ty.array(itemSchema)](src/tests/array.test.ts)\n- [ty.tuple(...itemSchema)](src/tests/tuple.test.ts)\n- [ty.dict(itemSchema)](src/tests/dict.test.ts)\n\n**Set-Theoretic:**\n\n- [ty.const(data as const)](src/tests/const.test.ts)\n- [ty.union(leftSchema, rigthSchema)](src/tests/union.test.ts)\n- [ty.intersection(leftSchema, rigthSchema)](src/tests/intersection.test.ts)\n\n**Structural:**\n\n- [ty.optional(schema)](src/tests/optional.test.ts)\n\n**Recursion:**\n\n- [ty.lazy(() =\u003e schema)](src/tests/lazy.test.ts)\n\n## Contributions\n\nTo make a contribution, fork this project and create a pull request.\n\nPlease read the [STYLE-GUIDE.md](STYLE-GUIDE.md) before you change the code.\n\nRemember to add yourself to [AUTHORS](AUTHORS).\nYour line belongs to you, you can write a little\nintroduction to yourself but not too long.\n\n## License\n\n[GPLv3](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxieyuheng%2Fty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxieyuheng%2Fty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxieyuheng%2Fty/lists"}