Skip to content
NirelcPublic

About

Super lightweight and simple type system library

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

15 Commits

Folders and files

Repository files navigation

microtype

Super lightweight and simple type system library like zod, but faster, smaller, and with fewer functions.

We doesn't use eval, Function or something like this, because we're staying web-friendly

Install

NPM

npm install @nirelc/microtype

Bun

bun intall @nirelc/microtype

Usage

Imports

Microtype can be imported with wildcard or with only required types

// with only required types import
import { … } from '@nirelc/microtype';

// with a wildcard import
import * as t from '@nirelc/microtype';

Your first type

Microtype simillar with valibot and other type system libs, because of this, you will easily understand our syntax

import { object, string } from "@nirelc/microtype";

// typescript
type UserData = {
  username: string;
  email?: string;
};

// microtype
const PostSchema = object({
  username: string(),
  email: string().optional(),
});

type PostData = typeof PostSchema.static;

const data = PostSchema.parse({
  username: "system",
  should: "strip",
});

We provide some useful features with schema chaining

const PostSchema = object({
  email: string().min(5).max(128).optional(),
  version: number().default(1),
});

API

All types support <type>.default(<value>) syntax.

Now we support these types:

String

// typescript
type Username = string;

// microtype
const UsernameSchema = string();

// extra fields
const UsernameExtraSchema = string().min(1).max(24).default("root");

Numbers

// typescript
type Version = number;

// microtype
// any number and floats
const VersionSchema = number(); // or `float()` as alias

// only integer (float will trigger error)
const VersionIntSchema = integer();

// integer with pre-built validators
// supports: uinteger, u8, u16, u32, i8, i16, i32
const SmallVersionSchema = u8();

// extra fields
// e.g value should equals 1 <= value <= 3 and should parse string as number and drop float support
const VersionExtraSchema = number().min(1).max(3).coerce(true).integer(true);

Literal

// typescript
type Username = "root";

// microtype
const UsernameSchema = literal("root");

Boolean

// typescript
type IsActive = boolean;

// microtype
const IsActiveSchema = boolean();

// coerce string and number to boolean
const IsActiveCoerceSchema = boolean().coerce(true);

Optional

Supported separated type optional(<schema>), also can be chained with <schema>.optional()

// typescript
type Email = string | undefined;

const EmailSchema = string().optional();
// const EmailSchema = optional(string());

Transform

Supported separated type transform(<schema>, <TransformFn>), also can be chained with <schema>.transform(<transformFn>).

const StrBoolSchema = string().transform((value) =>
  ["yes", "true", "1", "on"].includes(value.toLowerCase()),
);
// const StrBoolSchema = transform(string(), (value) =>
//   ["yes", "true", "1", "on"].includes(value.toLowerCase()),
// );

Unions

// typescript
type Username = "root" | "user";

// microtype
const UsernameSchema = union([literal("root"), literal("user")];

// with nested union
const UsernameWithNestedSchema = union([literal("root"), union([literal("user")])])

Arrays

// typescript
type Versions = number[];

// microtype
const VersionsSchema = array(number());

// extra fields
// min 1 item, max 3 items
const VersionsLimitedSchema = array(number()).min(1).max(3);

// array.length should be equal 3
const VersionsWithLengthScheam = array(number()).length(3);

Objects

All unknown fields will be deleted

// typescript
type User = {
  username: string;
  email?: string;
  status: "banned" | "active";
};

// microtype
const VersionsSchema = object({
  username: string(),
  // email: string().optional()
  email: optional(string()),
  status: union([literal("banned"), literal("active")]),
});

Standard Schema

All schemas implement Standard Schema, so they can be passed directly to libraries that accept it (Elysia, tRPC, Hono, TanStack Form, react-hook-form, etc.)

import {
  object,
  string,
  number,
  type Input,
  type Output,
} from "@nirelc/microtype";

const UserSchema = object({
  username: string(),
  version: number().default(1),
});

type UserInput = Input<typeof UserSchema>; // { username: string; version?: number | undefined }
type UserOutput = Output<typeof UserSchema>; // { username: string; version: number }

// or use the Standard Schema interface directly
const result = UserSchema["~standard"].validate({ username: "system" });
// { value: { username: "system", version: 1 } } or { issues: [{ message, path }] }

Benchmarks

You can run benchmarks in bench dir.

Results

In this benchmark, we compare microtype with other popular type system libraries: valibot, arktype, typebox, and zod.

The results below are from the best of 5 runs for Microtype.

Schema creation + parse

Create a new schema and parse 1000 values

name median
microtype 595.65 µs
valibot 2.30 ms
typebox 12.17 ms
zod 67.36 ms
arktype 94.95 ms

Global schema

Global schema (parsing with pre-created schema) with parse 1000 values

name median
typebox [compiled]* 19.20 µs
arktype* 37.36 µs
microtype 366.14 µs
zod 505.66 µs
valibot 533.27 µs
typebox 7.25 ms

* - arktype and typebox [compiled] uses precompile, because of this, it has better performance for global schema

Bundle size

We using a micro test case for create a type object schema + parse for all libs

name unminified minified gzip
microtype 10.75 KB 5.56 KB 1.57 KB
valibot 13.17 KB 5.81 KB 1.96 KB
typebox 110.37 KB 48 KB 13.69 KB
zod 166.69 KB 86.92 KB 24.71 KB
arktype 284.33 KB 155.4 KB 47.22 KB

Why

Q: Why did you make another type system lib?

  • idk, just for fun

About

Super lightweight and simple type system library

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages