@arrirpc/schema

中文文档
0.85.0发布于 2026/10/03MITTypeScriptESM + CJS近 30 天下载 1万

一个 Typescript 验证器和 schema 构建器,可以编译到其他语言. 两人的灵感很多 类型框 财务报告和审定财务报表 佐德语Name 当设计此库时。 这个

中文使用文档
文档目录52 节
  1. 项目哲学
  2. 加入RFC 8927
  3. 目录
  4. 安装
  5. 基本示例
  6. 使用@ arrirpc/ 服务器
  7. 汇编到其他语言
  8. 安装 ARRI CI
  9. 创建您的 Arri 配置
  10. 创建并导出您的外观
  11. 运行代码生成器
  12. 示例输出
  13. 可树动导入
  14. 为什么这不是默认?
  15. 支持类型
  16. 初级
  17. 数字
  18. 矩阵/ 列表
  19. 对象
  20. 记录/地图
  21. 歧视工会
  22. 递归类型
  23. 修改器
  24. 可选
  25. 无效
  26. 无法定义
  27. 克隆
  28. 扩展
  29. 奥米
  30. 选择
  31. 部分
  32. 公用事业
  33. 校验
  34. 解析
  35. 解析不安全
  36. 胁迫
  37. 胁迫不安全
  38. 序列化
  39. 序列化不安全
  40. 错误
  41. 敬杰森·斯克马
  42. 元数据
  43. 实例
  44. 简称 ID
  45. 编译验证器
  46. 基准
  47. 对象
  48. 整数
  49. 发展
  50. 大楼
  51. 运行单元测试
  52. 基准制定

阿里·斯克马

一个 Typescript 验证器和 schema 构建器,可以编译到其他语言. 两人的灵感很多 类型框 财务报告和审定财务报表 佐德语Name 当设计此库时。 此库也支持 标准大纲 意思是它可以和任何接受标准schema的第三方库一起使用.

在盖子下,这个图书馆构造 阿里类型定义这些定义可以传给 阿里·CLI 为Arri支持的任何客户端语言生成代码。 最后,这个图书馆还有一个 JIT 编译器 产生比Zod快100倍的预编译验证器.

项目哲学

该项目的目标如下:

  • 便携式类型定义
  • 高性能验证、解析和序列化
  • 分析错误和序列化错误的一致错误报告

我并不想支持Typescript系统的所有功能, 甚至是JSON的所有可能的表示。 目标是通过这个库定义的数据模型可以被多种编程语言用作真理的来源. JSON和Typescript必须加以限制才能做到这一点.

加入RFC 8927

最初,这个图书馆是用来为 Json 类型定义然而,随着时间的推移,对内部计划的一些部分进行了修改,以便更好地实现Arri RPC的目标。 其中一些修改包括:

  • 添加对 64 位整数的支持
  • 替换 additionalProperties 字段为 strict 以默认允许额外属性.
  • 限制 ref 仅用于递归引用.

目录

安装

# npm
npm install @arrirpc/schema

# pnpm
pnpm install @arrirpc/schema

基本示例

import { a } from '@arrirpc/schema';

const User = a.object({
    id: a.string(),
    name: a.string(),
});

type User = a.infer<typeof User>;

// returns ResultSuccess<User>
a.parse(User, `{"id": "1", "name": "John Doe"}`);
// returns ResultFailure
a.parse(User, `{"id": "1", "name": null}`);

// returns true
a.validate(User, { id: '1', name: 'John Doe' });
// returns false
a.validate(User, { id: '1', name: null });

// outputs valid json
a.serialize(User, { id: '1', name: 'John Doe' });

// JIT compiled validator (faster but server-side only)
const $$User = a.compile(User);
$$User.validate({ id: '1', name: 'John Doe' });
$$User.parse(`{"id": "1", "name": "John Doe"}`);
$$User.serialize({ id: '1', name: 'John Doe' });

使用@ arrirpc/ 服务器

见 这里 详细情况.

import { a } from '@arrirpc/schema';
import { defineRpc } from '@arrirpc/server';

export default defineRpc({
    params: a.object({
        name: a.string(),
    }),
    response: a.object({
        message: a.string(),
    }),
    handler({ params }) {
        // can now access params.name here
        return {
            message: `Hello ${params.name}`,
        };
    },
});

汇编到其他语言

使用此库定义的所有计划可以编译为其它语言 阿里·CLI。 。 。 .

安装 ARRI CI

# npm
npm i --save-dev arri

# pnpm
pnpm i --save-dev arri

创建您的 Arri 配置

import { defineConfig, generators } from 'arri';

export default defineConfig({
    generators: [
        // add your generators here
        generators.rustClient({
            // options
        }),
        generators.dartClient({
            // options
        }),
    ],
});

创建并导出您的外观

使用 createAppDefinition 帮助您为 ARRI CLI 输出您的计划 .

// definitions.ts
import { createAppDefinition } from 'arri';
import { a } from '@arrirpc/schema';

const User = a.object('User', {
    id: a.string(),
    name: a.optional(string()),
    email: a.nullable(a.string()),
    createdAt: a.timestamp({ description: 'When the user was created' }),
    updatedAt: a.timestamp(),
});

export default createAppDefinition({
    definitions: {
        User,
    },
});

运行代码生成器

# npm
npx arri codegen ./definitions.ts

# pnpm
pnpm arri codegen ./definitions.ts

还有你的功劳 现在,每当您的计划更新时,您都可以重运行此命令 .

示例输出

// dart output

class User {
  final String id;
  final String? name;
  final String? email;
  /// when the user was created
  final DateTime createdAt;
  final DateTime updatedAt;
  const User({
     required this.id,
     this.name,
     required this.email,
     required this.createdAt,
     required this.updatedAt,
  });

  // implementation details
}
// rust output

pub struct User {
  id: String,
  name: String,
  name: Option<String>,
  email: Option<String>,
  // when the user was created
  created_at: DateTime<FixedOffset>,
  updated_at: DateTime<FixedOffset>,
}

impl ArriModel for User {
  // implementation details
}
// kotlin output

data class User(
  val id: String,
  val name: String?,
  val email: String? = null,
  /**
   * When the user was created
   */
  val createdAt: Instant,
  val updatedAt: Instance,
) {
  // implementation details
}

见 这里 用于列出所有官方支持的语言生成器.

可树动导入

对于关心捆绑大小的人,您可以使用Arri的可选模块导入语法. 这使得捆绑者可以在建设时从JS捆绑中去除未使用的Arri功能. 您也可以在您的代码库中使用 灌溉/预模进口 规则.

使用模块导入语法Arri的捆绑大小可小到4kb,取决于您导入的函数数.

// tree-shakeable (no `a` prefix)
import { string, boolean, object } from '@arrirpc/schema';
const User = object({
    id: string(),
    name: string(),
    isAdmin: boolean(),
});

// tree-shakeable (with `a` prefix)
import * as a from '@arrirpc/schema';
const User = a.object({
    id: a.string(),
    name: a.string(),
    isAdmin: a.boolean(),
});

// NOT tree-shakeable
import { a } from '@arrirpc/schema';
const User = a.object({
    id: a.string(),
    name: a.string(),
    isAdmin: a.boolean(),
});

点击 这里 看Arri Schema的捆绑尺寸 和生态系统的其余部分相比.

为什么这不是默认?

只是个人偏好。 我发现手动导入个人函数是一种糟糕的开发者体验.

// not a fan
import { foo, bar, baz } from 'foo';

此外,明确出口 a 命名空间是指当我输入时 a.{something} tS语言服务器会自动完成可用的功能,即使我还没有导入 @arrirpc/schema 还没有。 如果我们没有那么明确的出口, 那你就不会得到自动完成 a.{something} 直到您添加 import * as a 线条到您的文件.

// this has to be added before you get autocomplete for `a.{whatever}`
import * as a from '@arrirpc/schema';

但是,我明白,保持小的捆绑尺寸可能很重要 这就是为什么我允许两种选择:

// if you care about bundle size use one of these two
import * as a from '@arrirpc/schema';
import { string, object, etc } from '@arrirpc/schema';

// if you aren't as particular about bundle sizes then use this
import { a } from '@arrirpc/schema';

支持类型

初级

阿里·斯克马字体Arri 类型定义
a. 任何( )任意{}
a. 字符串( )字符串{"类型":"字符串"}
a. boolean () (中文(简体) )布尔{"类型":"boole"}
a. 时间戳( )日期{"类型":"时间戳"}
a. float32( )编号{"类型":"float32"}
a. float64 () (中文(简体) )编号{"类型":"float64"}
a.int8 () (中文(简体) )编号{"类型":"int8"}
a.int16 () (中文(简体) )编号{"类型":"int16"}
a.int32() (中文(简体) )编号{"类型":"int32"}
a.int64() (中文(简体) )大点{"类型":"int64"}
a. uint8( )编号{"类型":"int8"}
a.int16 () (中文(简体) )编号{"类型":"int16"}
a.int32() (中文(简体) )编号{"类型":"int32"}
a.int64() (中文(简体) )大点{"类型":"int64"}

数字

Enum 计划允许您指定一个预定义的已接受字符串列表

使用量

const Status = a.enumerator(['ACTIVE', 'INACTIVE', 'UNKNOWN']);
type Status = a.infer<typeof Status>; // "ACTIVE" | "INACTIVE" | "UNKNOWN";

a.validate(Status, 'BLAH'); // false
a.validate(Status, 'ACTIVE'); // true

输出的 ATD

{
    "enum": ["ACTIVE", "INACTIVE", "UNKNOWN"]
}

矩阵/ 列表

使用量

const MyList = a.array(a.string());
type MyList = a.infer<typeof MyList>; // string[];

a.validate(MyList, [1, 2]); // false
a.validate(MyList, ['hello', 'world']); // true

输出的 ATD

{
    "elements": {
        "type": "string"
    }
}

对象

使用量

const User = a.object({
    id: a.string(),
    email: a.string(),
    created: a.timestamp(),
});
type User = a.infer<typeof User>; // { id: string; email: string; created: Date; }

a.validate(User, {
    id: '1',
    email: '[email protected]',
    created: new Date(),
}); // true
a.validate(User, {
    id: '1',
    email: null,
    created: new Date(),
}); // false

输出的 ATD

{
    "properties": {
        "id": {
            "type": "string"
        },
        "email": {
            "type": "string"
        },
        "created": {
            "type": "timestamp"
        }
    }
}

严格模式

默认情况下, @arrirpc/schema 在验证对象时会忽略并删除任何额外的属性 。 如果您想要在存在额外属性时验证失败, 请修改 strict 选项.

const UserStrict = a.object(
    {
        id: a.string(),
        name: a.string(),
        created: a.timestamp(),
    },
    {
        strict: true,
    },
);

a.parse(UserStrict, {
    id: '1',
    name: 'johndoe',
    created: new Date(),
    bio: 'my name is joe',
}); // fails parsing because of the additional field "bio"

输出的 ATD

{
    "properties": {
        "id": {
            "type": "string"
        },
        "email": {
            "type": "string"
        },
        "created": {
            "type": "timestamp"
        }
    },
    "strict": true
}

记录/地图

使用量

const R = a.record(a.boolean());
type R = a.infer<typeof R>; // Record<string, boolean>

a.validate(R, {
    hello: true,
    world: false,
}); // true;
a.validate(R, {
    hello: 'world',
}); // false;

输出的 ATD

{
    "values": {
        "type": "boolean"
    }
}

歧视工会

使用量

const Shape = a.discriminator('type', {
    RECTANGLE: a.object({
        width: a.float32(),
        height: a.float32(),
    }),
    CIRCLE: a.object({
        radius: a.float32(),
    }),
});
type Shape = a.infer<typeof Shape>; // { type: "RECTANGLE"; width: number; height: number; } | { type: "CIRCLE"; radius: number; }

// Infer specific sub types of the union
type ShapeTypeRectangle = a.inferSubType<Shape, 'type', 'RECTANGLE'>; // { type "RECTANGLE"; width: number; height: number; };
type ShapeTypeCircle = a.inferSubType<Shape, 'type', 'CIRCLE'>; // { type "CIRCLE"; radius: number; }

a.validate(Shape, {
    type: 'RECTANGLE',
    width: 1,
    height: 1.5,
}); // true
a.validate(Shape, {
    type: 'CIRCLE',
    radius: 5,
}); // true
a.validate(Shape, {
    type: 'CIRCLE',
    width: 1,
    height: 1.5,
}); // false

输出的 ATD

{
    "discriminator": "type",
    "mapping": {
        "RECTANGLE": {
            "properties": {
                "width": {
                    "type": "float32"
                },
                "height": {
                    "type": "float32"
                }
            }
        },
        "CIRCLE": {
            "properties": {
                "radius": {
                    "type": "float32"
                }
            }
        }
    }
}

递归类型

您可以使用 a.recursive 帮手 此函数接受另一个输出对象计或歧义计的函数.

需要注意的一点是,类型推论对递归式计划并不正确. 为了满足 Typescription, 您需要定义类型, 然后把它传递给函数作为通用 .

此外,建议为任何递归计划确定标识。 如果未指定 arri 将自动生成 .


如果一些 TS 向导知道如何使类型推论自动为这些递归性计划工作,那么尽管我担心需要对现有类型系统进行重大重构,却可以随意打开一个PR.

使用量

// the recursive type must be defined first
type BinaryTree = {
    left: BinaryTree | null;
    right: BinaryTree | null;
};

// pass the type to the helper
const BinaryTree = a.recursive<BinaryTree>(
    (self) =>
        // the resulting schema must be an object or discriminator
        // it also must match the type you pass into the generic parameter
        // or TS will yell at you
        a.object({
            left: a.nullable(self),
            right: a.nullable(self),
        }),
    {
        id: 'BinaryTree',
    },
);

a.validate(BinaryTree, {
    left: {
        left: null,
        right: {
            left: null,
            right: null,
        },
    },
    right: null,
}); // true
a.validate(BinaryTree, {
    left: {
        left: null,
        right: {
            left: true,
            right: null,
        },
    },
    right: null,
}); // false

输出的 ATD

{
    "properties": {
        "left": {
            "ref": "BinaryTree",
            "nullable": true
        },
        "right": {
            "ref": "BinaryTree",
            "nullable": true
        }
    },
    "metadata": {
        "id": "BinaryTree"
    }
}

修改器

可选

使用 a.optional() 使对象字段具有可选性.

const User = a.object({
    id: a.string(),
    email: a.optional(a.string()),
    date: a.timestamp();
})

/**
 * Resulting type
 * {
 *   id: string;
 *   email?: string | undefined;
 *   date: Date;
 * }
 */

输出的 ATD

{
    "properties": {
        "id": {
            "type": "string"
        },
        "date": {
            "type": "timestamp"
        }
    },
    "optionalProperties": {
        "email": {
            "type": "string"
        }
    }
}

无效

使用 a.nullable() 使特定类型无效

const name = a.nullable(a.string());

/**
 * Resulting type
 * string | null
 */

输出的 ATD

{
    "type": "string",
    "nullable": true
}

无法定义

这类似于 a.optional() 但是,在初始化对象时,仍然需要按键.

const Foo = a.object({
    foo: a.undefinable(a.string()),
});
type Foo = a.infer<typeof Foo>;

const fooInstance: Foo = {
    // this field must still be present
    // while with a.optional() we could omit the key
    foo: undefined,
};

就解析和验证而言,此函数与 a.optional()。 。 。 .

const User = a.object({
    id: a.string(),
    email: a.undefinable(a.string()),
    date: a.timestamp();
})

/**
 * Resulting type (Notice how the email key is still required)
 * {
 *   id: string;
 *   email: string | undefined;
 *   date: Date;
 * }
 */

输出的 ATD

{
    "properties": {
        "id": {
            "type": "string"
        },
        "date": {
            "type": "timestamp"
        }
    },
    "optionalProperties": {
        "email": {
            "type": "string"
        }
    }
}

克隆

复制另一个图案而不复制 它的元数据使用 a.clone() 帮助者

const A = a.object(
    {
        a: a.string(),
        b: a.float32(),
    },
    { id: 'A' },
);
console.log(A.metadata.id); // "A"

const B = a.clone(A);
console.log(B.metadata.id); // undefined

扩展

以 a.extend() 帮手.

const A = a.object({
    a: a.string(),
    b: a.float32(),
});
// { a: string; b: number; }

const B = a.object({
    c: a.timestamp(),
});
// { c: Date }

const C = a.extend(A, B);
// { a: string; b: number; c: Date }

奥米

使用 a.omit() 创建新对象计划,并删除某些属性

const A = a.object({
    a: a.string(),
    b: a.float32(),
});
// { a: string; b: number; }

const B = a.omit(A, ['a']);
// { b: number; }

选择

使用 a.pick() 创建新对象计划,其中包含来自父对象的属性子集

const A = a.object({
    a: a.string(),
    b: a.float32(),
    c: a.timestamp(),
});
// { a: string; b: number; c: Date; }

const B = a.pick(A, ['a', 'c']);
// { a: string; c: Date; }

部分

使用 a.partial() 以创建新的对象方案,使母方案的所有属性都具有可选性.

const A = a.object({
    a: a.string(),
    b: a.float32(),
    c: a.timestamp(),
});
// { a: string; b: number; c: Date; }

const B = a.partial(A);
// { a: string | undefined; b: number | undefined; c: Date | undefined; }

公用事业

校验

打电话 a.validate() 以验证一个输入 相对于 arri 计划。 这种方法也起到类型保护的作用,所以任何 any 或者说 unknown 通过验证的类型会自动为已验证的字段获得自动完成

const User = a.object({
    id: a.string(),
    name: a.string(),
});
a.validate(User, true); // false
a.validate(User, { id: '1', name: 'john doe' }); // true

if (a.validate(User, someInput)) {
    console.log(someInput.id); // intellisense works here
}

解析

打电话 a.parse() 把JSON的绳子和Arri的图案联系起来 它也会处理正常对象的剖析.

const User = a.object({
    id: a.string(),
    name: a.string(),
});

// returns Result<User>
const result = a.parse(User, jsonString);
if (result.success) {
    // something when wrong with parsing
    console.log(result.errors);
} else {
    // parsing was successful
    console.log(result.value);
}

解析不安全

备用版本改为 parse() 将投出一个 ValidationException 如果解析失败.

const User = a.object({
    id: a.string(),
    name: a.string(),
});

// can throw an error
const result = a.parseUnsafe(User, jsonString);
console.log(result);

胁迫

a.coerce() 将尝试将输入转换为正确的类型。 回返a Result<T>

const A = a.object({
    a: a.string(),
    b: a.boolean(),
    c: a.float32(),
});

a.coerce(A, {
    a: '1',
    b: 'true',
    c: '500.24',
});
// { success: true, value: { a: '1', b: true, c: 500.24 } };

胁迫不安全

a.coerceUnsafe() 是替代 a.coerce() 如果胁迫失败, 就会出错

const A = a.object({
    a: a.string(),
    b: a.boolean(),
    c: a.float32(),
});

a.coerceUnsafe(A, someInput); // returns T but can throw an error

序列化

a.serialize() 将输入并将其序列化为有效的 JSON 字符串。 此返回 Result<string>

const User = a.object({
    id: a.string(),
    name: a.string(),
});

const result = a.serialize(User, { id: '1', name: 'john doe' });
if (result.success) {
    console.log(result.value);
    // '{"id":"1","name":"john doe"}''
}

注意此函数不验证输入 。 因此,如果您正在以任何或未知类型传递到此函数,建议您先验证它.

序列化不安全

a.serializeUnsafe() 是替代 a.serialize() 返回 JSON 字符串,但可以投出错误.

const User = a.object({
    id: a.string(),
    name: a.string(),
});

const result = a.serialize(User, { id: '1', name: 'john doe' }); // might throw an error
// '{"id":"1","name":"john doe"}''

注意此函数不验证输入 。 因此,如果您正在以任何或未知类型传递到此函数,建议您先验证它.

错误

使用 a.errors() 以获取给定输入的所有验证错误.

const User = a.object({
    id: a.string(),
    date: a.timestamp(),
});

a.errors(User, { id: 1, date: 'hello world' });
/**
 * [
 *   {
 *     instancePath: "/id",
 *     schemaPath: "/properties/id/type",
 *     message: "Expected string",
 *   },
 *   {
 *     instancePath: "/date",
 *     schemaPath: "/properties/id/type",
 *     message: "Expected instanceof Date",
 *   }
 * ]
 *
 */

敬杰森·斯克马

使用 a.toJsonSchema() 将 Arri 计划转换为 杰森·斯克马 格式。 这对于:

  • 编辑器支持 - YAML/JSON文件使用Arri定义的chemas可以在VS代码,IntelliJ等中自动完成.
  • 互通性 - 与使用JSON Schema的工具(OpenAPI、文件生成器等)相结合
  • 配置验证 - 定义配置文件的用户可以参考JSON Schema URL进行验证
const User = a.object(
    {
        id: a.string(),
        name: a.string(),
        email: a.nullable(a.string()),
        role: a.enumerator(['USER', 'ADMIN']),
        createdAt: a.timestamp(),
    },
    { id: 'User', description: 'A user in the system' },
);

const jsonSchema = a.toJsonSchema(User, {
    $id: 'https://example.com/schemas/user.json',
    title: 'User Schema',
});

结果 :

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/schemas/user.json",
    "title": "User Schema",
    "type": "object",
    "properties": {
        "id": { "type": "string" },
        "name": { "type": "string" },
        "email": { "type": ["string", "null"] },
        "role": { "type": "string", "enum": ["USER", "ADMIN"] },
        "createdAt": { "type": "string", "format": "date-time" }
    },
    "required": ["id", "name", "email", "role", "createdAt"]
}

选项

选项类型说明
$id字符串这个 $id 用于根图
title字符串用于根图的名称
description字符串用于根图的描述
$schema字符串JSON Schema 草稿版本( 默认 : https://json-schema.org/draft/2020-12/schema(中文(简体) )

类型绘图

阿里·斯克马JSON Schema 等效词
a.any(){} (任何一个)
a.string(){ "type": "string" }
a.boolean(){ "type": "boolean" }
a.timestamp(){ "type": "string", "format": "date-time" }
a.float32/64(){ "type": "number" }
a.int8/16/32(){ "type": "integer", "minimum": X, "maximum": Y }
a.uint8/16/32(){ "type": "integer", "minimum": 0, "maximum": Y }
a.int64/uint64(){ "type": "string", "pattern": "^-?[0-9]+$" }
a.enumerator(){ "type": "string", "enum": [...] }
a.array(){ "type": "array", "items": {...} }
a.object(){ "type": "object", "properties": {...}, "required": [...] }
a.record(){ "type": "object", "additionalProperties": {...} }
a.discriminator(){ "oneOf": [...] } 与歧视者
a.nullable()添加数 "null" 键入数组

元数据

元数据在跨语言代码生成时被使用. Arri 计划允许您指定以下元数据字段:

  • id - 将在任何arri客户端生成器中用作类型名称
  • 说明 - 将在任何生成类型之上添加为说明注释
  • is depressed - 将标记任何生成的代码,并标记目标语言的去pression 注释

实例

包含此元数据的计划 :

// metadata object
const BookSchema = a.object(
    {
        title: a.string(),
        author: a.string(),
        publishDate: a.timestamp(),
    },
    {
        id: 'Book',
        description: 'This is a book',
    },
);

将在编码时生成类似类型 .

字体

/**
 * This is a book
 */
interface Book {
    title: string;
    author: string;
    publishDate: Date;
}

锈

/// This is a book
struct Book {
    title: String,
    author: String,
    publish_date: DateTime<FixedOffset>
}

达特

/// This is a book
class Book {
    final String title;
    final String author;
    final DateTime publishDate;
    const Book({
        required this.title,
        required this.author,
        required this.publishDate,
    });
}

科特林语Name

/**
 * This is a book
 */
data class Book(
    val title: String,
    val author: String,
    val publishDate: Instant,
)

简称 ID

因为身份证对制作简洁的型号名非常重要. Arri验证还提供了定义物体、歧视者和递归型的识别特征的简写.

// ID will be set to "Book"
const BookSchema = a.object('Book', {
    title: a.string(),
    author: a.string(),
    publishDate: a.timestamp(),
});

// ID will be set to "Message"
const MessageSchema = a.discriminator('Message', 'type', {
    TEXT: a.object({
        userId: a.string(),
        content: a.string(),
    }),
    IMAGE: a.object({
        userId: a.string(),
        imageUrl: a.string(),
    }),
});

// ID will be set to "BTree"
const BinaryTreeSchema = a.recursive('BTree', (self) =>
    a.object({
        left: a.nullable(self),
        right: a.nullable(self),
    }),
);

编译验证器

@arrirpc/schema 具有高性能的JIT编译器,将Arri Schemas转化为高度优化的验证,解析,强制,和串行功能. 汇编的结果还落实了以下内容: 标准大纲 界面,意思是它可以传递到任何接受标准-schema的库中.

const User = a.object({
    id: a.string(),
    email: a.nullable(a.string()),
    created: a.timestamp(),
});

const $$User = a.compile(User);

$$User.validate(someInput);
$$User.parse(someJson);
$$User.parseUnsafe(someJson);
$$User.coerce(someObject);
$$User.coerceUnsafe(someObject);
$$User.serialize({ id: '1', email: null, created: new Date() });
$$User.serializeUnsafe({ id: '1', email: null, created: new Date() });

在大多数情况下,编译的验证器将比标准公用事业快得多。 然而,在汇编计划方面有一些间接费用,因此,理想的做法是每个验证器都汇编一次。 此外,还利用下列方法创建了由此产生的方法: new Function() 因此,它们只能用于你控制的后端服务器等环境中. 它们不会在浏览器环境中工作.

您还可以使用 a.compile 用于代码生成。 通过 true 因为第二个参数将确保编译结果能够使您访问生成的函数机构。 此功能默认已禁用 v0.76.0 以减少不必要的内存使用。 (如果这些大字符串不会被使用的话,就不必随身携带. )

// pass true to the second parameter to get access to the generated function bodies
const $$User = a.compile(User, true);

$$User.compiledCode.validate; // the generated validation code
$$User.compiledCode.parse; // the generated parsing code
$$User.compiledCode.coerce; // the generated coercion code
$$User.compiledCode.serialize; // the generated serialization code

基准

最后更新:2025-06-09T18:41:32.823Z

所有的基准都在我的个人桌面上运行。 您可以查看使用方法 ./基准/弧。 。 。 .

OS - Pop!_OS 22.04 LTS
CPU - AMD Ryzen 9 5900 12-Core Processor
RAM - 32GB
Graphics - AMD® Radeon rx 6900 xt

对象

这些基准采用了以下类型。 在上述各图书馆都建立了等效计划.

interface TestUser {
    id: number; // integer,
    role: 'standard' | 'admin' | 'moderator';
    name: string;
    email: string | null;
    createdAt: number; // integer
    updatedAt: number; // integer
    settings:
        | {
              preferredTheme: 'light' | 'dark' | 'system';
              allowNotifications: boolean;
          }
        | undefined;
    recentNotifications: Array<
        | {
              type: 'POST_LIKE';
              userId: string;
              postId: string;
          }
        | {
              type: 'POST_COMMENT';
              userId: string;
              postId: string;
              commentText: string;
          }
    >;
}

对象验证 - 好输入

图书馆行动
Arri (编译)54 207 983 (中文(简体) )
类型框(已编译)42 991 276 (单位:千美元)
方舟类型(单位:千美元)
蒂皮亚28 500 181美元
Arri (编译) - 标准Schema19,420,723 (英语)
Ajv - JSON Schema (编译)11 612 359美元
Ajv - JSON 舍马11,337,540人 (单位:千美元)
佐德/v4区3 080 359 (中文(简体) )
亚利2,719,630人次 (简体中文)
Arri - 标准Schema760 346 (韩语)
类型框720,807 (中文(简体) )
维利博特594 403 (简体中文)
佐德语Name463 499 (韩语)

对象验证 - 坏输入

图书馆行动
Arri (编译)60 871 312美元)
类型框(已编译)47,747,764 (单位:千美元)
蒂皮亚31,195,589个
Arri (编译) - 标准Schema8 314 141 (简体中文)
Ajv - JSON Schema (编译)4 523 107 (中文(简体) )
Ajv - JSON 舍马4 315 160个
亚利3 992 012个
类型框891 805 (中文(简体) )
Arri - 标准计划757 845 (韩语)
维利博特496 579 (简体中文)
佐德语Name352 986 (简体中文)
方舟类型149 079 (中文(简体) )
佐德/v4区100 355个

对象解析 - 好输入

图书馆行动
JSON.parse (英语)801 513个
JSON.parse + 类型框(已编译)754 820 (中文(简体) )
Arri (编译)753,155 (韩语)
JSON.parse + 方舟类型748,862 (中文(简体) )
Arri (编译) - 标准Schema745,964 (英语)
Typia (json.create ValidateParse) (英语)726,365 (中文(简体) )
JSON.parse + Zod/v4 (英语)555 511 (中文(简体) )
亚利365,992 (韩语)
Arri - 标准Schema365 640 (韩语)
JSON.parse + 瓦利博特319 333个
JSON.parse + 佐德语285,161 (单位:千美元)
JSON.parse + 类型框215 169 (中文(简体) )

对象解析 - 坏输入

图书馆行动
JSON.parse (英语)846 547 (中文(简体) )
Arri (编译)779 979 (英语)
Arri (编译) - 标准Schema718,259个
Typia (json.create ValidateParse) (英语)552,892 (韩语)
亚利414 169 (中文(简体) )
Arri (标准计划)391,092 (中文(简体) )
JSON.parse + 瓦利博特289 960 (简体中文)
JSON.parse + 佐德语220 650 (中文(简体) )
JSON.parse + 方舟类型120 295 (中文(简体) )
JSON.parse + 类型框(已编译)99,136 (简体中文)
JSON.parse + Zod/v4 (英语)80 506 (简体中文)
JSON.parse + 类型框77 380美元 (单位:千美元)

对象序列化

图书馆行动
Arri (编译)3,984,935人次 (简体中文)
Arri (编译) - 验证和序列化3 583 501 (中文(简体) )
蒂皮亚1,793,677人 (中文(简体) )
JSON 强调1 645 335美元)
Typia - 验证和序列化1 540 510美元)
亚利450 120美元

强制对象

图书馆行动
Arri (编译)19,370,221 (韩语)
佐德/v4区2,267,229人次
亚利738 461 (中文(简体) )
佐德语Name450 168 (中文(简体) )
类型框403 602 (韩语)

整数

以下基准衡量每个库以单一整数运行的速度.

导入验证

图书馆行动
Arri (编译)188 029 099 (中文(简体) )
类型框(已编译)186 595 706 (简体中文)
Ajv - JSON Schema (编译)182 332 718 (中文(简体) )
Arri (编译) - 标准Schema108 964 372 (单位:千美元)
Arri - 标准Schema108 193 957 (中文(简体) )
亚利84 093 924 (中文(简体) )
蒂皮亚58,164,521人 (中文(简体) )
方舟类型57,782,710 (单位:千美元)
Ajv - JSON 舍马50,350,825 (单位:千美元)
类型框46 450 527美元
维利博特22 202 298 (中文(简体) )
佐德/v4区18 948 463 (中文(简体) )
佐德语Name1 269 812美元 (单位:千美元)

Int 验证( 失败输入)

图书馆行动
类型框(已编译)188 306 861 (单位:千美元)
Arri (编译)186 071 486 (中文(简体) )
Ajv - JSON Schema (编译)69,251,304 (单位:千美元)
蒂皮亚60 060 635 (中文(简体) )
类型框44,860,799 (英语)
亚利39 998 319 (中文(简体) )
Ajv - JSON 舍马25 013 168 (简体中文)
Arri (编译) - 标准Schema15,998,638个
Arri - 标准Schema11,765,466人 (单位:人)
维利博特9 831 763美元 (单位:千美元)
佐德语Name766 604 (中文(简体) )
方舟类型439 401 (韩语)
佐德/v4区100,168 (单位:千美元)

插入解析( 好输入)

图书馆行动
Arri (编译)136,350,248 (单位:千美元)
亚利49 111 714美元)
JSON.parse () (英语)21,047,855 (英语)

INT 解析( 失败输入)

图书馆行动
Arri (编译)60 790 411美元 (单位:千美元)
JSON.parse () (英语)12,746,512个
亚利9 824 069 (中文(简体) )

序列化

图书馆行动
Arri (编译) - 验证和序列化194 120 420 (中文(简体) )
Arri (编译)186 143 375 (中文(简体) )
蒂皮亚107 523 528美元
亚利59 302 746 (中文(简体) )
Typia - 验证和序列化47,194,163 (韩语)
JSON 强调17 049 686 (单位:千美元)

强制( 良好输入)

图书馆行动
亚利50,428,605美元 (单位:千美元)
类型框34 878 937 (中文(简体) )
Ajv - JSON 舍马32,125,175 (简体中文)
佐德/v4区14 351 655 (中文(简体) )
佐德语Name1 197 013 (中文(简体) )

强迫( 错误输入)

图书馆行动
亚利10 088 606 (简体中文)
类型框8 117 032人次 (单位:千美元)
Ajv - JSON 舍马6 979 847 (简体中文)
佐德语Name762 348 (韩语)
佐德/v4区99 086 (简体中文)

发展

大楼

运行 nx build @arrirpc/schema 来建造图书馆.

运行单元测试

运行 nx test @arrirpc/schema 通过 Vitest 执行单位测试

基准制定

运行 nx benchmark @arrirpc/schema 执行基准

版本与发布记录

@arrirpc/schema 共发布 91 个版本,首次发布于 2024/05/14;过去 12 个月发布了 11 个版本。

版本发布日期距今
0.85.0latest2026/10/031 个月前
0.84.12026/08/043 个月前
0.84.02026/08/043 个月前
0.83.12026/07/143 个月前
0.83.02026/07/143 个月前
0.82.02026/05/225 个月前

其他发布通道:beta → 0.76.3-beta.0。

关于 @arrirpc/schema 的常见问题

@arrirpc/schema 是什么?

一个 Typescript 验证器和 schema 构建器,可以编译到其他语言. 两人的灵感很多 类型框 财务报告和审定财务报表 佐德语Name 当设计此库时。 这个

如何安装 @arrirpc/schema?

在项目目录运行 npm install @arrirpc/schema,或使用 pnpm add / yarn add / bun add。

@arrirpc/schema 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@arrirpc/schema 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@arrirpc/schema 可以商用吗?

@arrirpc/schema 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@arrirpc/schema 的下载量有多少?

根据 npm 官方下载统计,@arrirpc/schema 在 2026/10/07 – 2026/11/05 这 30 天内被下载 10,054 次,日均约 335 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@arrirpc/schema 还在维护吗?

最新版本 0.85.0 发布于 2026/10/03(1 个月前);至今共发布 91 个版本,其中过去 12 个月发布了 11 个;首次发布于 2024/05/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。