Skip to content
26 changes: 13 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"peerDependencies": {
"@sinclair/typebox": "^0.34.30",
"valibot": "^1.0.0",
"zod": "^3.24.1"
"zod": "^3.25.0"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.2",
Expand Down
118 changes: 97 additions & 21 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,32 +48,38 @@ const result = validator['~standard'].validate({ // const result: StandardS

TypeMap is a syntax frontend and compiler backend for the [TypeBox](https://github.com/sinclairzx81/typebox), [Valibot](https://github.com/fabian-hiller/valibot) and [Zod](https://github.com/colinhacks/zod) runtime type libraries. It offers a common TypeScript syntax for type construction, a runtime compiler for high-performance validation and type translation from one library to another.

TypeMap supports both Zod v3 and Zod v4, with distinct APIs for each version, allowing projects to smoothly transition between versions as needed.

TypeMap is written as an advanced type mapping system for the TypeBox project. It is designed to accelerate remote type libraries on TypeBox infrastructure as well enabling TypeBox to integrate with remote type library infrastructure via reverse type remapping. This project also offers high-performance validation for frameworks that orientate around the [Standard Schema](https://github.com/standard-schema/standard-schema) TypeScript interface.

License: MIT

## Contents

- [Install](#Install)
- [Usage](#Usage)
- [Overview](#Overview)
- [Example](#Example)
- [Mapping](#Section-Mapping)
- [Syntax](#Mapping-Syntax)
- [TypeBox](#Mapping-TypeBox)
- [Valibot](#Mapping-Valibot)
- [Zod](#Mapping-Zod)
- [Syntax](#Section-Syntax)
- [Types](#Syntax-Types)
- [Options](#Syntax-Options)
- [Parameters](#Syntax-Parameters)
- [Generics](#Syntax-Generics)
- [Static](#Section-Static)
- [Json Schema](#Json-Schema)
- [Tree Shake](#Tree-Shake)
- [Compile](#Compile)
- [Benchmark](#Benchmark)
- [Contribute](#Contribute)
- [Install](#install)
- [Usage](#usage)
- [Overview](#overview)
- [Contents](#contents)
- [Example](#example)
- [Mapping](#mapping)
- [Syntax](#syntax)
- [TypeBox](#typebox)
- [Valibot](#valibot)
- [Zod](#zod)
- [Zod4](#zod4)
- [Syntax](#syntax-1)
- [Types](#types)
- [Options](#options)
- [Parameters](#parameters)
- [Generics](#generics)
- [Static](#static)
- [Json Schema](#json-schema)
- [Tree Shake](#tree-shake)
- [Compile](#compile)
- [Benchmark](#benchmark)
- [Test](#test)
- [Results](#results)
- [Contribute](#contribute)

## Example

Expand Down Expand Up @@ -211,6 +217,21 @@ const V = Zod(v.string()) // const V: z.ZodString
const Z = Zod(z.boolean()) // const Z: z.ZodBoolean (Zod)
```

<a name="Mapping-Zod4"></a>

### Zod4

Use the `Zod4` function to translate types and syntax into Zod v4 types:

```typescript
import { Zod4 } from '@sinclair/typemap'

const S = Zod4('string[]') // const S: z.ZodArray<...> (Syntax)
const T = Zod4(t.Number()) // const T: z.ZodNumber (TypeBox)
const V = Zod4(v.string()) // const V: z.ZodString (Valibot)
const Z = Zod4(z.boolean()) // const Z: z.ZodBoolean (Zod)
```

<a name="Section-Syntax"></a>

## Syntax
Expand Down Expand Up @@ -369,6 +390,20 @@ const T = TypeBoxFromZod(z.object({ // const T: TObject<{
})) // }>
```

For Zod v4, you can use the corresponding import:

```typescript
import { TypeBoxFromZod4 } from '@sinclair/typemap' // Use TypeBox & Zod v4, Tree Shake Valibot

import { z } from 'zod/v4'

const T = TypeBoxFromZod4(z.object({ // const T: TObject<{
x: z.number(), // x: TNumber;
y: z.number(), // y: TNumber;
z: z.number() // z: TNumber;
})) // }>
```

## Compile

Use the `Compile` function to compile TypeBox, Valibot and Zod on TypeBox infrastructure ([Example](https://www.typescriptlang.org/play/?moduleResolution=99&module=199#code/JYWwDg9gTgLgBAbzgYQuYAbApgGjgLQgBM4BfOAMyjTgHIABAZ2ADsBjDAQ2CgHoYAnmCwhOYWgCgJvXijRhMWAsTgAVIVilsILRvABunDMCKcY0OAF456bAApCROwAMEEuB4AeALjgsAriAARlhQOO4eAr4BwaHhHnAAXtGBIVASpM4AlFlaOnpwAEoAjFZwhsam5lAAdMgAFlhsANZ2SD5wxXhRcABMeMlwAMxkWQlwMnAAgmxsWNhQZlhEUpMAyjCcLKZQJGtsjaLSvMdwNedwAO71wAdwjPUQ-hgk9Zz6SiFYLH6cIMt0DZbHYkABqRhMZmgkgk2l08EKvTKFUh1QA2rQAH56YGcXa0AC6NRRVSwbTgHS6cB6-SSvhGpCyQA))
Expand All @@ -393,6 +428,22 @@ const R1 = validator.Check({ x: 1, y: 2, z: 3 }) // Accelerated
const R2 = validator['~standard'].validate({ x: 1, y: 2, z: 3 })
```

You can also compile Zod v4 types:

```typescript
import { Compile, Zod4 } from '@sinclair/typemap'

// Compile Zod v4 Type

const validator = Compile(Zod4(`{
x: number,
y: number,
z: number
}`))

const R1 = validator.Check({ x: 1, y: 2, z: 3 }) // Accelerated with Zod v4
```

## Benchmark

This project manages a small benchmark that compares validation performance using Zod, Valibot, and TypeBox validators. For more comprehensive community benchmarks, refer to the [runtime-type-benchmarks](https://github.com/moltar/typescript-runtime-type-benchmarks) project.
Expand Down Expand Up @@ -426,7 +477,32 @@ Results show the approximate elapsed time to complete the given iterations
└─────────┴────────────────┴────────────────────┴────────────┴────────────┘
```


Using [bun](https://bun.sh) and the latest (2025-06-14) versions of each library, the results show there is still an order-of-magnitude advantage to compiling.

```ts
┌───┬──────────────┬──────────────────┬────────────┬──────────┐
│ │ library │ using │ iterations │ elapsed │
├───┼──────────────┼──────────────────┼────────────┼──────────┤
│ 0 │ valibot │ valibot │ 10000000 │ 792 ms │
│ 1 │ valibot │ typebox:value │ 10000000 │ 1625 ms │
│ 2 │ valibot │ typebox:compile │ 10000000 │ 177 ms │
└───┴──────────────┴──────────────────┴────────────┴──────────┘
┌───┬──────────────┬──────────────────┬────────────┬──────────┐
│ │ library │ using │ iterations │ elapsed │
├───┼──────────────┼──────────────────┼────────────┼──────────┤
│ 0 │ zod │ zod │ 10000000 │ 4553 ms │
│ 1 │ zod │ typebox:value │ 10000000 │ 1739 ms │
│ 2 │ zod │ typebox:compile │ 10000000 │ 214 ms │
└───┴──────────────┴──────────────────┴────────────┴──────────┘
┌───┬──────────────┬──────────────────┬────────────┬──────────┐
│ │ library │ using │ iterations │ elapsed │
├───┼──────────────┼──────────────────┼────────────┼──────────┤
│ 0 │ zod v4 │ zod v4 │ 10000000 │ 1404 ms │
│ 1 │ zod v4 │ typemap:zod4 │ 10000000 │ 1214 ms │
│ 2 │ zod v4 │ typebox:value │ 10000000 │ 2294 ms │
│ 3 │ zod v4 │ typebox:compile │ 10000000 │ 310 ms │
└───┴──────────────┴──────────────────┴────────────┴──────────┘
```

## Contribute

Expand Down
59 changes: 52 additions & 7 deletions src/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ THE SOFTWARE.
import * as t from '@sinclair/typebox'
import * as v from 'valibot'
import * as z from 'zod'
import { z as z4 } from 'zod/v4'

/** Structural Type for Syntax */
export type SyntaxType = string
Expand All @@ -38,6 +39,8 @@ export type TypeBoxType = t.TSchema
export type ValibotType = v.BaseSchema<any, any, v.BaseIssue<any>>
/** Structural Type for Zod */
export type ZodType = z.ZodTypeAny | z.ZodEffects<any>
/** Structural Type for Zod4 */
export type Zod4Type = z4.ZodTypeAny

// ------------------------------------------------------------------
// Syntax
Expand Down Expand Up @@ -67,19 +70,61 @@ export function IsValibot(type: unknown): type is v.AnySchema {
type['~standard'].vendor === 'valibot'
)
}
// ------------------------------------------------------------------
// Common Zod Detection
// ------------------------------------------------------------------
/**
* Returns true if the given value has the standard Zod vendor property
* This is common to both Zod v3 and Zod v4 types
*/
// prettier-ignore
function IsZodVendor(type: unknown): boolean {
if (!t.ValueGuard.IsObject(type)) return false;
if (!t.ValueGuard.HasPropertyKey(type, '~standard')) return false;

const standardProp = (type as any)['~standard'];
if (!t.ValueGuard.IsObject(standardProp)) return false;
if (!t.ValueGuard.HasPropertyKey(standardProp, 'vendor')) return false;

return standardProp.vendor === 'zod';
}

// ------------------------------------------------------------------
// Zod
// ------------------------------------------------------------------
/** Returns true if the given value is a Zod type */
/** Returns true if the given value is a Zod v3 type */
// prettier-ignore
export function IsZod(type: unknown): type is z.ZodTypeAny {
if (!IsZodVendor(type)) return false;

const obj = type as Record<string, unknown>;

// Check for Zod v3 specific properties:
// 1. Has '_def' property (not 'def')
// 2. Does not have Zod v4 specific methods like 'meta'
return (
t.ValueGuard.IsObject(type) &&
t.ValueGuard.HasPropertyKey(type, '~standard') &&
t.ValueGuard.IsObject(type['~standard']) &&
t.ValueGuard.HasPropertyKey(type['~standard'], 'vendor') &&
type['~standard'].vendor === 'zod'
)
t.ValueGuard.HasPropertyKey(obj, '_def') &&
!t.ValueGuard.HasPropertyKey(obj, 'meta')
);
}

// ------------------------------------------------------------------
// Zod4
// ------------------------------------------------------------------
/** Returns true if the given value is a Zod4 type */
// prettier-ignore
export function IsZod4(type: unknown): type is z4.ZodTypeAny {
if (!IsZodVendor(type)) return false;

const obj = type as Record<string, unknown>;

// Check Zod v4 specific properties:
// 1. Has 'def' property
// 2. Has specific v4 methods like 'meta'
return (
t.ValueGuard.HasPropertyKey(obj, 'def') &&
t.ValueGuard.HasPropertyKey(obj, 'meta')
);
}
// ------------------------------------------------------------------
// Signature
Expand Down
14 changes: 14 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export * from './syntax/syntax-from-syntax'
export * from './syntax/syntax-from-typebox'
export * from './syntax/syntax-from-valibot'
export * from './syntax/syntax-from-zod'
export * from './syntax/syntax-from-zod4'
export { type TSyntax, Syntax } from './syntax/syntax'

// ------------------------------------------------------------------
Expand All @@ -54,6 +55,7 @@ export * from './typebox/typebox-from-syntax'
export * from './typebox/typebox-from-typebox'
export * from './typebox/typebox-from-valibot'
export * from './typebox/typebox-from-zod'
export * from './typebox/typebox-from-zod4'
export { type TTypeBox, TypeBox } from './typebox/typebox'

// ------------------------------------------------------------------
Expand All @@ -63,6 +65,7 @@ export * from './valibot/valibot-from-syntax'
export * from './valibot/valibot-from-typebox'
export * from './valibot/valibot-from-valibot'
export * from './valibot/valibot-from-zod'
export * from './valibot/valibot-from-zod4'
export { type TValibot, Valibot } from './valibot/valibot'

// ------------------------------------------------------------------
Expand All @@ -72,4 +75,15 @@ export * from './zod/zod-from-syntax'
export * from './zod/zod-from-typebox'
export * from './zod/zod-from-valibot'
export * from './zod/zod-from-zod'
export * from './zod/zod-from-zod4'
export { type TZod, Zod } from './zod/zod'

// ------------------------------------------------------------------
// Zod4
// ------------------------------------------------------------------
export * from './zod4/zod4-from-syntax'
export * from './zod4/zod4-from-typebox'
export * from './zod4/zod4-from-valibot'
export * from './zod4/zod4-from-zod4'
export * from './zod4/zod4-from-zod'
export { type TZod4, Zod4 } from './zod4/zod4'
Loading