JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 42
  • Score
    100M100P100Q74544F
  • License MIT

High-performance TypeScript validation library with WebAssembly backend

Package Exports

  • dhi

Readme

DHI Logo

DHI

npm version License: Apache 2.0 TypeScript

🚀 DHI — High‑Performance TypeScript Validation

DHI is a blazing‑fast TypeScript validation library with two faces:

  • A modern, typed‑first API (recommended)
  • A familiar Zod‑like facade for easy migration

It’s built for applications that validate large datasets efficiently while preserving compile‑time type safety and a great DX.

🚀 Performance at a glance

DHI significantly outperforms other validation libraries through two complementary approaches:

DHI outperforms general‑purpose validators by combining JS fast paths (iterative deep‑object validators, array‑of‑object fast path) with a fused per‑schema JS validator that collapses multiple property reads into a single monomorphic function.

  • Typed‑first API (recommended): fast, type‑safe, zero WASM overhead
  • WASM/Rust (optional): batch primitives and deep trees with cross‑language optimizations

Comprehensive Benchmark Results

TypeScript-First API Performance

Simple 4-Field Required Schema (1M items):
  DHI:  40.67ms (24,591,023 ops/sec)
  Zod:  58.16ms (17,193,063 ops/sec)
  Speedup: 1.43x

Simple 4-Field with Optional (1M items):
  DHI:  49.92ms (20,032,966 ops/sec)
  Zod:  53.90ms (18,554,459 ops/sec)
  Speedup: 1.08x

Mixed Valid/Invalid Data (500K items):
  DHI:  385.17ms (1,298,142 ops/sec)
  Zod:  1209.65ms (413,342 ops/sec)
  Speedup: 3.14x

Average speedup: 1.88x

Benchmarks run on Mac Studio with Bun runtime

📖 Usage

DHI provides compile-time type safety similar to Yup's approach:

import {
  object,
  string,
  number,
  boolean,
  array,
  record,
  union,
  discriminatedUnion,
  optional,
  nullable,
  model,
  type ObjectSchema,
  type TypedInfer
} from 'dhi';

// Define your TypeScript interface
interface User {
  name: string;
  age?: number;
  email: string;
  active: boolean;
}

// Method 1: Direct schema with compile-time type checking
const userSchema: ObjectSchema<User> = object({
  name: string(),
  age: optional(number()),
  email: string(),
  active: boolean()
});

// Method 2: Named model with enhanced error messages
const UserModel = model('User', {
  name: string(),
  age: optional(number()),
  email: string(),
  active: boolean()
});

// ❌ This would cause a compile-time error:
// const badSchema: ObjectSchema<User> = object({
//   name: number(), // Type error: number is not assignable to string
// });

// Type inference
type InferredUser = TypedInfer<typeof userSchema>; // User
type ModelUser = TypedInfer<typeof UserModel>; // User

// Validation
const userData = {
  name: "John Doe",
  age: 30,
  email: "john@example.com",
  active: true
};

// Single validation
const user = userSchema.validate(userData);

// Safe validation
const result = userSchema.safeParse(userData);
if (result.success) {
  console.log('Valid user:', result.data);
} else {
  console.log('Validation error:', result.error);
}

// Batch validation (ultra-fast for simple schemas)
const users = [userData, /* ... more users */];
const validationResults = userSchema.validateBatch(users);

// Discriminated unions (fast dispatch)
const Event = discriminatedUnion('type', {
  click: object({ type: string(), x: number(), y: number() }),
  page_view: object({ type: string(), url: string() }),
  purchase: object({ type: string(), orderId: string(), value: number() })
});

// Record/dictionary validation (fused loop, no allocations)
const StringMap = record(string()); // Schema<Record<string, string>>
const ok = StringMap.validate({ a: 'x', b: 'y' });

### Performance Comparison with Yup

```typescript
// Yup approach
import { object, number, string, ObjectSchema } from 'yup';

interface Person {
  name: string;
  age?: number;
  sex: 'male' | 'female' | 'other' | null;
}

const yupSchema: ObjectSchema<Person> = object({
  name: string().defined(),
  age: number().optional(),
  sex: string<'male' | 'female' | 'other'>().nullable().defined(),
});

// DHI approach (1.43x faster)
import { object, string, number, optional, nullable, type ObjectSchema } from 'dhi';

const dhiSchema: ObjectSchema<Person> = object({
  name: string(),
  age: optional(number()),
  sex: nullable(string()) // Note: enum validation coming soon
});

धि: Intellect, understanding, wisdom.

DHI is designed to be fast, type-safe, and easy to use—offering a familiar API similar to Zod, but with performance that leaves it far behind. Benchmarks on complex validations with new types (1,000,000 items) show(Benchmarks are available in the benchmarks folder):

  • Results:
    • DHI: 2661.79ms
    • Zod: 5832.30ms
  • Validations per second:
    • DHI: 375,687
    • Zod: 175,360

Benchmark Execution Time

Benchmark Validations per Second

DHI leverages WebAssembly to accelerate validation tasks, ensuring that even complex validations with new types are handled with remarkable speed.


Features

  • WebAssembly-Powered Validation: Ultra-fast performance using WebAssembly.
  • TypeScript-First Design: Seamless integration with TypeScript for strong typing.
  • Familiar API: Similar to Zod, making it easy to adopt.
  • Batch Validation Support: Validate large batches of items efficiently.
  • Rich Type System: Supports a wide array of types.

📥 Installation

npm install dhi
bun add dhi

Fun Fact: Small Browser Payload

For browsers, DHI ships a compact payload:

  • JS + WASM total: 46 KB gzip (158 KB raw)
  • Breakdown (gzip): typed.js ~6.9 KB, zod-compat.js ~2.2 KB, core.js ~2.0 KB, wasm.js ~1.8 KB, index.js ~0.6 KB, dhi_core_bg.wasm ~32.9 KB
  • Note: The dhi_core.node binary (~369 KB) is Node-only and not shipped to browsers.

🔨 Legacy WASM API (optional)

import { dhi } from 'dhi';

const UserSchema = await dhi.object({
  name: dhi.string(),
  age: dhi.number(),
  email: dhi.string(),
  tags: dhi.array(dhi.string())
});

const result = UserSchema.validate({
  name: "John",
  age: 30,
  email: "john@example.com",
  tags: ["user", "admin"]
});

console.log(result.success);

Notes

  • Initialization: The legacy WASM wrapper handles async initialization internally (via ensureWasmInitialized()); callers usually don’t need to invoke it directly. If you want to pre-warm on startup, you can import { ensureWasmInitialized } from 'dhi/dist/wasm' and await ensureWasmInitialized().
  • Shipped assets: The npm package includes dist/dhi_core.js (wasm-bindgen glue) and dist/dhi_core_bg.wasm. A native Node binding (dist/dhi_core.node) may be present for host builds but is not used in browsers.
  • No postinstall build: Artifacts are prebuilt in dist/; installs work out of the box.

🏗️ Supported Types (Typed API)

  • string, number, boolean
  • object({...})
  • array(schema)
  • record(valueSchema)
  • union([...]), discriminatedUnion(key, mapping)
  • Modifiers: optional(schema), nullable(schema)
  • Helpers: model(name, shape), TypedInfer

Note: The temporary Zod‑compat layer exposes a limited subset of Zod APIs (e.g., z.object, z.string, z.array, z.record, z.enum, basic .optional()/.nullable(), .parse/.safeParse). It exists to ease migration and may be removed in a future major release.

Zod‑Compat (Migration Aid)

// One‑liner migration: replace your zod import
import { z } from 'dhi';

const User = z.object({ id: z.string(), name: z.string() });
const r = User.safeParse({ id: '1', name: 'A' });

🎓 Advanced Features

  • Optional Fields: optional(string())
  • Nullable Fields: nullable(number())
  • Discriminated unions: discriminatedUnion('type', { ... })
  • Array‑of‑object fast path: inner object with ≤4 primitive fields
  • Batch Validation: schema.validateBatch(items)

📈 Performance details

Recent real‑world suites (on a Mac Studio) show: (2025-08-28)

  • Setup

    • DHI: v0.1.4
    • Zod: v4.1.4
    • Script: benchmarks/benchmark2.ts
    • Dataset: 1,000,000 mixed valid/invalid user-like objects
  • Results

    • DHI: 498.13ms (800,091 valid)
    • Zod: 647.54ms (800,091 valid)
  • Validations per second

    • DHI: 2,007,501
    • Zod: 1,544,300
  • Performance Gain

    • DHI is 30% faster than Zod v4
    • 463,201 more validations per second
  • Optimizations Applied

    • Strict fast path with SIMD-style unrolled loops for primitive schemas (≤4 fields)
    • Boolean-returning internal validation to eliminate Result allocations
    • Precomputed schema analysis and flattened field vectors
    • Cached JS keys with single Reflect.get per field
    • Increased chunk size (32k) and wasm-opt with -O3 + SIMD

Benchmarks live in benchmarks/ and include both comprehensive micro‑benchmarks and realistic datasets:

  • Benchmark 1 (1,000,000 items):

    • DHI: 2661.79ms
    • Zod: 5832.30ms
    • Validations per second: DHI: 375,687 vs. Zod: 175,360
  • Benchmark 2 (1,000,000 items):

    • DHI: 2885.60ms
    • Validations per second: DHI: 346,548

These results showcase the performance edge DHI offers, especially for applications requiring massive data validations.


🧪 Build & Release

  • Build everything locally: bash scripts/build.sh
  • CI/CD: publishing to npm is handled by a GitHub workflow on release (requires NPM_TOKEN).

License

This project is licensed under the Apache 2.0 License.


Author

Rach Pradhan


Repository

For more information, bug reports, or contributions, please visit the GitHub repository.


🌟 DHI: Where Sanskrit wisdom meets modern TypeScript validation — delivering unmatched speed, precision, and reliability for your applications.


🧰 Zod‑like DX (migration aid)

For teams familiar with Zod v4, DHI ships a small facade that mirrors common ergonomics. Use it to migrate gradually; for the best performance and type‑safety, prefer the typed‑first API above.

  • Import the facade and wait for initialization once:
import { z, dhiReady, Infer } from 'dhi';

await dhiReady; // ensures WASM is ready so constructors are sync
  • Define schemas similarly to Zod:
const User = z.object({
  id: z.string(),
  name: z.string(),
  age: z.number(),
  tags: z.array(z.string()),
  status: z.enum('active', 'inactive', 'banned'), // also supports array form: z.enum(['active','inactive','banned'])
  deletedAt: z.date().optional(),
  lastLogin: z.date().nullable(),
});
  • Parse or safe-parse:
const parsed = User.parse({ id: '1', name: 'Jane', age: 42, tags: [], status: 'active' });
const result = User.safeParse({ id: 1 });
if (!result.success) {
  console.log(result.error.issues); // [{ code, path, message }]
}
  • Type inference:
type User = Infer<typeof User>;

Notes:

  • This preview covers core constructors: string, number, boolean, date, bigint, symbol, any, unknown, never, undefined, null, void, plus object, array, record, and enum.
  • Modifiers: .optional(), .nullable() are supported.
  • Roadmap: union, discriminatedUnion, literal, tuple, map, set, refine/superRefine, transform/pipe, coerce, default/catch/nullish/readonly/brand, and richer error codes.