ArkType:最接近 TypeScript 的运行时校验
如果说 zod 给人的感觉是“用一套顺手的 API 来描述类型”,那 ArkType 走的是另一条路:
尽量直接用 TypeScript 风格的表达,把类型带进运行时。
这也是它最容易被记住的原因。
很多运行时校验库都在解决同一个问题:
- 编辑器里有类型
- 运行时输入不可信
- 需要一份 schema 既能推导类型,又能真的执行校验
但 ArkType 的手感确实和别家不太一样,因为它定义 schema 时,看起来更像直接在写类型。
为什么说它和 TypeScript 很近
官方入门页的写法基本就是:
import { type } from "arktype"
const User = type({
name: "string",
platform: "'android' | 'ios'",
"versions?": "(number | string)[]"
})
type User = typeof User.infer
如果你本来就熟 TypeScript,第一次看到这段大多会有个很直接的感觉:
这不像是在学一套全新的 DSL,更像是在把熟悉的类型表达拿来运行。
这点和 zod 很不一样。
zod 更像:
const UserSchema = z.object({
name: z.string(),
platform: z.enum(["android", "ios"]),
versions: z.array(z.union([z.number(), z.string()])).optional(),
})
两种都能把事情做成,只是入口完全不一样。
一个最小例子
import { type } from "arktype"
const Post = type({
title: "string > 0",
status: "'draft' | 'published'",
"tags?": "string[]"
})
const result = Post({
title: "",
status: "archived"
})
如果输入不合法,ArkType 不会给你那种“看起来像过了,其实没真校验”的错觉。它会直接返回结构化错误。
它最适合什么人
1. 本来就很吃 TypeScript 表达能力的人
如果你平时就经常写:
- 联合类型
- 可选字段
- 数组和嵌套对象
- 字面量约束
那 ArkType 的入门成本通常不会太高。
2. 不喜欢链式 API 写很长的人
有些人会觉得 zod 很顺,有些人会觉得:
z.string().min(1).max(50).regex(...)
链条一长,视觉上就越来越像在堆调用,而不是在写类型定义。
ArkType 在这点上会更统一一些。
3. 想把函数边界也纳入运行时校验的人
ArkType 2.2 之后,一个很有辨识度的能力是 type.fn。
const len = type.fn("string | unknown[]", ":", "number")(s => s.length)
这意味着你不只是校验对象,连函数参数和返回值都能一起收进去。
它和 Zod 的差别,别只看语法
真正的差别不只是“一个像字符串表达,一个像链式 API”。
更深一层看:
Zod 的重心
- 通用开发体验
- 社区生态
- 表单、服务端入口、AI schema 的广泛兼容
ArkType 的重心
- 类型表达和运行时尽量 贴近
- 函数边界、regex、约束表达更有辨识度
- 对“类型就是接口语言”这件事更执着
所以它不一定适合所有团队,但会特别对一部分团队的胃口。
什么时候我会优先考虑 ArkType
- 团队成员 TypeScript 基础比较好
- 项目里本来就很强调类型表达
- 希望 schema 定义尽量短、尽量像类型
- 想把函数边界校验也做得自然一点
什么时候我不会先推 ArkType
- 团队里很多人还没把 TypeScript 类型系统吃透
- 项目主要只是普通表单和简单接口
- 你更看重现成生态、社区样例和“拿来就用”
这时候 zod 往往会更稳一点。
放在整个站里,它更适合什么位置
虽然 ArkType 也是运行时校验库,但它值得单独写一篇,不是因为它用途更广,而是因为它和类型表达本身 贴得很近。
换句话说:
Zod更像工程边界工具ArkType更像类型系统思路延伸到运行时
所以现在把它放进 运行时校验 专题,同时在 TypeScript 专题里保留入口提示。结构会更整齐,读者也还是能很快意识到:这条路线和 TypeScript 的距离,比一般校验库近得多。
想继续往下看什么
如果你想看整体选型,不只盯 ArkType,继续读:
如果你想回到最常见的默认方案,再看: