{"id":15493469,"url":"https://github.com/sinclairzx81/type-adapters","last_synced_at":"2025-07-28T12:10:05.970Z","repository":{"id":255631000,"uuid":"852073503","full_name":"sinclairzx81/type-adapters","owner":"sinclairzx81","description":"Unified Adapter for Runtime Type Systems","archived":false,"fork":false,"pushed_at":"2024-09-05T12:04:50.000Z","size":19,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-22T19:55:59.852Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sinclairzx81.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2024-09-04T07:16:46.000Z","updated_at":"2025-01-28T02:43:06.000Z","dependencies_parsed_at":"2025-01-13T12:45:13.516Z","dependency_job_id":null,"html_url":"https://github.com/sinclairzx81/type-adapters","commit_stats":null,"previous_names":["sinclairzx81/type-adapters"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sinclairzx81/type-adapters","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Ftype-adapters","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Ftype-adapters/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Ftype-adapters/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Ftype-adapters/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sinclairzx81","download_url":"https://codeload.github.com/sinclairzx81/type-adapters/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Ftype-adapters/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267513796,"owners_count":24099824,"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-07-28T02:00:09.689Z","response_time":68,"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":[],"created_at":"2024-10-02T08:06:53.747Z","updated_at":"2025-07-28T12:10:05.897Z","avatar_url":"https://github.com/sinclairzx81.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Type Adapters\n\nUnified Adapter for Runtime Type Inference Libraries\n\n## Overview\n\nThis project is a prototype design for a unified type adapter for TypeScript Runtime Type libraries. This project aims to define a common adapter interface that can be used by frameworks for type inference and validation without the framework having to take on explicit library dependencies. The adapter is written in support of type inference dependency injection.\n\nThis project provides reference implementations for [arktype](https://github.com/arktypeio/arktype), [effect](https://github.com/Effect-TS/effect), [io-ts](https://github.com/gcanti/io-ts), [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts), [scale-codec](https://www.npmjs.com/package/scale-codec), [superstruct](https://github.com/ianstormtaylor/superstruct), [typebox](https://github.com/sinclairzx81/typebox), [valibot](https://github.com/fabian-hiller/valibot), [yrel](https://github.com/romelperez/yrel), [yup](https://github.com/jquense/yup) and [zod](https://github.com/colinhacks/zod) as well as tRPC client and server declarations to demonstrate a possible integration path for established frameworks.\n\nThe project is provided as a complimentary resource for the [standard-schema](https://github.com/standard-schema/standard-schema) working group. It seeks to explore a low impact design that would enable libraries to be integrated into down level frameworks without each library having to adopt a common type level interface.\n\nLicense MIT\n\n## Contents\n\n- [TypeAdapter and TRPC](./example/trpc.ts)\n- [TypeAdapter Interfaces](#TypeAdapter-Interfaces)\n- [TypeAdapter for Zod](#TypeAdapter-for-Zod)\n- [TypeAdapter for TypeBox](#TypeAdapter-for-TypeBox)\n- [TypeAdapter Example](#TypeAdapter-Example)\n- [Prior Art](#Prior-Art)\n\n\n\u003ca name=\"TypeAdapter-Interfaces\"\u003e\u003c/a\u003e\n\n## TypeAdapter Interfaces\n\nTypeAdapters consist of the following types and interfaces.\n\n```typescript\n// Used to specify library static inference\nexport interface TypeInference {\n  input: unknown\n  output: unknown\n}\n// Used to specify runtime validation + hold adapter inference\nexport abstract class TypeAdapter\u003cInference extends TypeInference = TypeInference\u003e {\n  inference: Inference = {} as never\n  abstract validate(schema: unknown, value: unknown): boolean\n}\n// Used to infer types on the adapter\nexport type Static\u003cA, Type\u003e = (\n  A extends TypeAdapter\u003cinfer I extends TypeInference\u003e \n    ? (I \u0026 { input: Type })['output']\n    : unknown\n)\n```\n\n\u003ca name=\"TypeAdapter-for-Zod\"\u003e\u003c/a\u003e\n\n## TypeAdapter for Zod\n\nThe following implements a type adapter for Zod.\n\n```typescript\nimport { TypeAdapter, TypeInference } from '@type-adapters/adapter'\nimport * as z from 'zod'\n\nexport interface Inference extends TypeInference {\n  output: this['input'] extends z.ZodSchema ? z.infer\u003cthis['input']\u003e : unknown\n}\nexport class Adapter extends TypeAdapter\u003cInference\u003e {\n  validate(schema: z.ZodSchema, value: unknown): boolean {\n    return schema.safeParse(value).success\n  }\n}\n```\n\n\u003ca name=\"TypeAdapter-for-TypeBox\"\u003e\u003c/a\u003e\n\n## TypeAdapter for TypeBox\n\nThe following implements a type adapter for TypeBox.\n\n```typescript\nimport { TypeAdapter, TypeInference } from '@type-adapters/adapter'\nimport { TSchema, StaticDecode } from '@sinclair/typebox'\nimport { Value } from '@sinclair/typebox/value'\n\nexport interface Inference extends TypeInference {\n  output: this['input'] extends TSchema ? StaticDecode\u003cthis['input']\u003e : unknown\n}\nexport class Adapter extends TypeAdapter\u003cInference\u003e {\n  validate(schema: TSchema, value: unknown): boolean {\n    return Value.Check(schema, value)\n  }\n}\n```\n\n\u003ca name=\"TypeAdapter-Example\"\u003e\u003c/a\u003e\n\n## TypeAdapter Example\n\nThe following defines a MethodBuilder that creates runtime type safe methods. The MethodBuilder accepts an abstract TypeAdapter interface via constructor argument which is used to infer method parameter and return type types. The example also shows Zod and TypeBox usage with the MethodBuilder. \n\nThe following aims to highlight `framework` and `type library` decoupling where only abstract TypeAdapter interfaces are known either side.\n\n```typescript\nimport { Static, TypeAdapter } from '@type-adapters/adapter'\n\ninterface MethodOptions { \n  input: unknown, \n  output: unknown \n}\n\nexport type Method\u003cAdapter extends TypeAdapter, Options extends MethodOptions\u003e = \n  (input: Static\u003cAdapter, Options['input']\u003e) =\u003e Static\u003cAdapter, Options['output']\u003e\n\n// Creates runtime type safe methods\nexport class MethodBuilder\u003cAdapter extends TypeAdapter\u003e {\n  // Adapter dependency injected on constructor\n  constructor(private readonly adapter: Adapter) { }\n\n  // Method return type inferred via Adapter + Input + Output properties.\n  public method\u003cOptions extends MethodOptions\u003e(options: Options, callback: Method\u003cAdapter, Options\u003e): Method\u003cAdapter, Options\u003e {\n    return (input: unknown) =\u003e {\n      if(!this.adapter.validate(options.input, input)) { throw Error('invalid input') }\n      const output = callback(input as never)\n      if(!this.adapter.validate(options.output, output)) { throw Error('invalid output') }\n      return output\n    }\n  }\n}\n\n// ------------------------------------------------------------------\n// Zod Usage\n// ------------------------------------------------------------------\n\nimport * as z from '@type-adapters/zod'\n\nconst add = new MethodBuilder(new z.Adapter()).method({\n  input: z.object({ \n    a: z.number(), \n    b: z.number() \n  }),\n  output: z.number()\n}, ({ a, b }) =\u003e a + b)\n\nadd({ a: 1, b: 2 }) // 3\n\n// ------------------------------------------------------------------\n// TypeBox Usage\n// ------------------------------------------------------------------\n\nimport * as t from '@type-adapters/typebox'\n\nconst sub = new MethodBuilder(new t.Adapter()).method({\n  input: t.Object({ \n    a: t.Number(), \n    b: t.Number() \n  }),\n  output: t.Number()\n}, ({ a, b }) =\u003e a + b)\n\nsub({ a: 1, b: 2 }) // -1\n```\n\n\u003ca name=\"Prior-Art\"\u003e\u003c/a\u003e\n\n## Prior Art\n\nFastify Type Providers\n\nhttps://fastify.dev/docs/latest/Reference/Type-Providers/\n\nTypeSchema\n\nhttps://github.com/decs/typeschema","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Ftype-adapters","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsinclairzx81%2Ftype-adapters","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Ftype-adapters/lists"}