✍️ 필사 모드: TypeScriptデータ検証 2026 — Zod·Valibot·ArkType·TypeBox·Effect Schema徹底比較(AIツール呼び出し時代のランタイム検証)
日本語プロローグ — すべてのAPI境界がスキーマを要求する時代
2022年のTypeScriptで「ランタイム検証は何を使う?」と聞けば答えはほぼ一つだった。Zod。その前はJoi、Yup、または手書きの型ガード。
2026年の同じ問いには候補が五つある。その間に多くのことが起きた。
- tRPCが標準になった。 すべての手続き入力にZodスキーマを差し込むパターンがフルスタックTSの基本文法になった。スキーマ = API境界。
- React Hook Form + zodResolverパターンがフォームのデファクト標準。 フォーム検証 = 同じスキーマ。
- AIツール呼び出し(function calling, tool use)がJSON Schemaを強制。 OpenAI・Anthropic・Geminiすべてがツール定義をJSON Schemaで受ける。TSスキーマからJSON Schemaを出せないと困ることになった。
- OpenAPI自動生成が再び熱い。 Hono・tRPC-openapi・
@asteasolutions/zod-to-openapi・TypeBoxの組み込みインターロップ。1スキーマでクライアント・サーバー・ドキュメントが同時に出る。 - バンドルサイズ = 金。 エッジランタイム・Cloudflare Workersに乗るコードが増えた。Zod 1MBの時代は過ぎたが、KB単位で計算する陣営が育った。
この流れが五つの陣営を作った。
- Zod 4 — デファクト標準。4.xでツリーシェイキング・パーサー再記述で弱点を正面から潰した。
- Valibot — 関数型モジュラーAPI。使った分しかバンドルに入らない。フロントエンドフォーム・エッジで強い。
- ArkType — TS文字列をスキーマに。
type({ email: 'string.email' })のような形式。TS推論との100%整合が武器。 - TypeBox — 書いたスキーマがそのままJSON Schema。Fastify・OpenAPI・AIツール呼び出しと直結。
- Effect Schema — Effectエコシステムの検証ツール。型付きエラー・合成可能な変換・双方向エンコーディングが武器。
- Yup / Joi / Superstruct — 生きているが新規採用は減り続ける。
この記事は2026年5月時点で、これらのライブラリを直接比較する。バンドル・推論・JSON Schema・非同期・OpenAPI・ランタイムコスト・エコシステムの7軸で。そして同じUserスキーマを5ライブラリで横並びに書く。
1章 · 風景 — データ検証ライブラリのマップ
まずは分類から。すべてが同じ位置にあるわけではない。
| 分類 | 代表ツール | ひとこと要約 |
|---|---|---|
| オブジェクトビルダー(チェーン) | Zod, Yup, Joi | z.string().email()スタイル。最も馴染みやすい。 |
| モジュラー関数 | Valibot | string([email()])。ツリーシェイクに優しい。 |
| TS文法をスキーマに | ArkType | TS型表現をそのままランタイムに。 |
| JSON Schemaネイティブ | TypeBox | 書いたものがJSON Schemaそのもの。 |
| 関数型 + Effect | Effect Schema | 型付きエラー、双方向エンコーディング。 |
| 軽量アサーション | Superstruct, io-ts | 小さく合成可能、やや古典的なスタイル。 |
この記事の焦点は太字に分かれる五つ — Zod・Valibot・ArkType・TypeBox・Effect Schema。Yup・Joi・Superstructは11章で短く扱う。
なぜこの五つか
- Zod 4 — 新規TypeScriptプロジェクトのデフォルト。tRPC・Next.js・React Hook Formどこでも登場。2024年発表のZod 4が2025〜2026に安定化してツリーシェイキングの弱点が大きく減った。
- Valibot — 2024年から本格成長。関数単位importで未使用コードがバンドルから落ちる。フロントエンド・エッジでシェアを急速に拡大。
- ArkType — TS表現をそのまま受ける発想の転換が魅力。v2安定化以降、新規プロジェクトの一筋。
- TypeBox — Fastify推奨、AJVと組み合わせると最速ランタイムの一つ。LLMにJSON Schemaを直送する場合の第一候補。
- Effect Schema — Effectフルスタックを行くチームの検証ツール。Effectを使わないなら採用理由は薄い。
2章 · 7軸比較マトリクス
詳細に入る前に全体像。
| 軸 | Zod 4 | Valibot | ArkType | TypeBox | Effect Schema |
|---|---|---|---|---|---|
| バンドル(コア) | 中 | 非常に小さい(モジュラー) | 小 | 非常に小さい | 大(Effect本体含む) |
| TS推論品質 | 非常に良い | 非常に良い | 最高(TS表現そのまま) | 良い | 非常に良い |
| JSON Schemaエクスポート | 外部パッケージ必要 | 外部パッケージ必要 | 組み込み | 組み込み(定義自体がJSON Schema) | 組み込み |
| 非同期検証 | あり | あり | 部分的 | なし(同期中心) | あり |
| OpenAPIエクスポート | zod-to-openapiなど | @valibot/to-json-schema | 組み込み | 組み込み(Fastify·AJV) | @effect/schema-openapi |
| ランタイムコスト | 速い(v4で大幅改善) | 非常に速い | 速い | 最速(AJVコンパイル時) | 中〜速 |
| エコシステム | 最大 | 急成長 | 中 | API/Fastify陣営 | Effectユーザー |
この表だけで決めてはいけない。次章から各ツールを正確に何ができて何ができないかを抑える。
3章 · Zod — 標準になった理由とZod 4の反撃
Zodは2020年登場以来、TypeScript検証のデファクト標準になった。理由は三つ。
- チェーンAPIの馴染みやすさ —
z.string().email().min(5)一行で意図が伝わる。Joi・Yupから来た人にとって学習コストはほぼゼロ。 z.infer型推論 — スキーマからTS型を自動導出。スキーマ = 型の真実の源泉。- エコシステム爆発 — tRPC・
@hookform/resolvers・OpenAI SDK・LangChain・Next.js Server Actions等が全部Zodをファーストクラスで受ける。
Zod 3時代の弱点
それでもZodは二つの批判を長く受けた。
- バンドルサイズ — チェーンAPIの性質上インデックス全体が一度に取り込まれるため、ツリーシェイキングが弱い。素の
z.string()だけでも数十KB。 - ランタイムコスト — 深いオブジェクトのパースが意外に重い。ホットパス(リクエストあたり数千回)で見えた。
Zod 4が変えたもの
Zod 4は2024年10月にベータ公開、2025年に本格GA。大きな変更が三つ。
- ツリーシェイカブルビルド — 未使用バリデータがバンドルから落ちる。
import { z } from 'zod'はそのままで、結果のバンドルが小さくなる。 - パーサー再記述 — 内部を単純化しホットパスを最適化。公式ベンチマークではv3に対し意味のある速度向上(数値はリリースノート参照)。
- ビルド分割 —
zodコアとzod/v4、ミニビルド(zod/v4-mini)が分かれた。後者はValibot級の超小型バンドルを狙う。
Zodで同じUserスキーマ
import { z } from 'zod'
const User = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150),
name: z.string().min(1),
})
type User = z.infer<typeof User>
const parsed = User.parse({ email: 'foo@example.com', age: 30, name: 'Foo' })
// ^ parsed: User
safeParseでエラーを値として受け取る。
const result = User.safeParse(unknown)
if (!result.success) {
// result.error is a ZodError; pretty issues at result.error.issues
console.error(result.error.flatten())
}
Zodの強み(2026)
- 最大のエコシステム。新規ライブラリ・SDKがほぼ自動でZodアダプタを提供。
- 4.xでバンドル・速度の弱点が大幅に縮小。
- 非同期検証(
z.string().refine(async ...))対応が滑らか。 - 学習リソースが圧倒的。
Zodの弱み(2026)
- 絶対値のバンドルは依然Valibotより大きい。エッジワーカーでKBを争う場面では候補外。
z.discriminatedUnion等の一部APIに学習コスト。- JSON Schemaエクスポートは外部パッケージ(
@asteasolutions/zod-to-openapi等)。ネイティブ対応は部分的。
4章 · Valibot — 関数型モジュラーでバンドルを削る
Valibotは2023年末〜2024年に爆発的に成長したライブラリ。コア哲学は一つ。
「基本を関数で書く。使わないコードはバンドルにない。」
Zodがz.string().email().min(5)ならValibotは関数合成。
import * as v from 'valibot'
const User = v.object({
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(150)),
name: v.pipe(v.string(), v.minLength(1)),
})
type User = v.InferOutput<typeof User>
const parsed = v.parse(User, { email: 'foo@example.com', age: 30, name: 'Foo' })
v.pipe(...)でバリデータを合成し、v.parse/v.safeParseで適用。関数はすべて名前付きエクスポート — 未使用はesbuild・Rollupが落とす。
バンドル差
公式サイトとコミュニティのベンチマークが示す絵。
v.string()を一度だけ使うと、Valibotで入るコードは数百バイトレベル。- 同じコードがZod 3では数十KB。Zod 4で大幅に縮小したが依然Valibotより大きい。
- 大きなスキーマ(多数のバリデータ)を全部使うと差は縮む。小さく始めるほどValibotが有利。
ValibotのBaseSchema API
Valibot 1.0 GA(2024)以降API安定。主要関数。
v.object,v.array,v.tuple,v.union,v.intersect,v.recordv.string,v.number,v.boolean,v.literal,v.date,v.bigintv.pipe(schema, ...actions)— バリデータ合成v.transform(fn),v.brand(name)— 変換・ブランド型
非同期検証は別途v.parseAsync/v.safeParseAsync。
Valibotの強み
- バンドルサイズ圧倒的 — フロントエンド・エッジでどこよりも小さい。
- 型推論品質 —
InferOutput・InferInput両方が正確。 - 関数型だから合成が容易 — 新しいバリデータを作るコストが低い。
- 急成長中のエコシステム — Standard Schema対応、
@valibot/to-json-schema、@hookform/resolvers/valibot。
Valibotの弱み
- API学習コスト — チェーンに慣れた人には最初ぎこちない。
- エラーメッセージのカスタマイズはやや手間。
- Zodアダプタを提供する一部ライブラリでValibotアダプタが未対応または遅れて追加。
- OpenAPIエクスポートでZod並みに厚いパッケージがない — 手書きが増える。
5章 · ArkType — TypeScript構文をそのままスキーマに
ArkTypeは2024年にv2をGAリリースして注目を集めた。発想が違う。
「TypeScript表現を文字列として受け取り、そのままランタイムスキーマにする。」
同じUserスキーマ。
import { type } from 'arktype'
const User = type({
email: 'string.email',
age: 'number.integer >= 0',
name: 'string > 0',
})
// type推論: TSが表現を正確に理解
type User = typeof User.infer
const out = User({ email: 'foo@example.com', age: 30, name: 'Foo' })
if (out instanceof type.errors) {
console.error(out.summary)
} else {
// out is the validated value
}
肝は'number.integer >= 0'のような表現がTSコンパイラによって正確な型に推論されること。ArkTypeは自前のミニDSLを作り、TSテンプレートリテラル型でパースする。結果として手書きのTS型とスキーマが100%一致する。
ArkTypeの差別点
- TS表現そのまま —
'string | number'、'(string | number)[]>=2'等が馴染みやすい。 - 型ファースト —
typeof User.inferが即時に使える。追加の.infer呼び出しコストなし(型レベル)。 - JSON Schemaエクスポート組み込み —
User.toJsonSchema()一行。 - ランタイム性能 — コンパイル済みバリデータ — スキーマ定義時に内部で検証関数を予めビルド。
ArkType オブジェクト定義の別形
文字列だけでなくTSオブジェクトをそのまま渡せる。
import { type } from 'arktype'
const Post = type({
id: 'number.integer',
title: 'string > 0',
tags: 'string[]',
author: {
id: 'number',
name: 'string',
},
publishedAt: 'Date',
})
ArkTypeの強み
- TS親和性が最高 — TSをよく知っている人にとって学習コストはほぼゼロ。
- JSON Schema組み込み — 外部パッケージ不要。
- ランタイム高速 — コンパイル済みバリデータ。
- 関数呼び出しがスキーマ =
User(value)— APIが直感的。
ArkTypeの弱み
- エコシステムがまだ小さい — tRPC・React Hook FormアダプタはあるがZodほど厚くない。
- エラーメッセージの日本語化・カスタマイズ資料が少ない。
- 非同期検証は部分対応 — 同期中心の設計。
- DSL文字列に慣れが必要 —
'number.integer >= 0'は最初は魔法のように感じる。
6章 · TypeBox — 書いたものがそのままJSON Schema
TypeBoxは2021年登場後、Fastify陣営で愛されてきたが、AIツール呼び出し時代に再注目された。
「私が書いたスキーマがそのままJSON Schema。AJVでコンパイルすれば最速ランタイム。」
同じUserスキーマ。
import { Type, Static } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
const User = Type.Object({
email: Type.String({ format: 'email' }),
age: Type.Integer({ minimum: 0, maximum: 150 }),
name: Type.String({ minLength: 1 }),
})
type User = Static<typeof User>
const ok = Value.Check(User, unknown)
const errors = [...Value.Errors(User, unknown)]
Type.Object({ ... })が返す値はJSON Schemaそのもの。JSON.stringify(User)すれば標準JSON Schemaドキュメントになる。
AJV結合 — 最速のランタイム
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
const ajv = addFormats(new Ajv())
const check = ajv.compile(User)
const ok = check(value) // コンパイル済み関数を直接呼ぶ — 非常に速い
AJVはJSON Schemaを受け取り、V8親和的なコードで検証関数をビルドする。結果は一般にこのカテゴリで最速のランタイム検証。
TypeBox + Fastify
import Fastify from 'fastify'
const app = Fastify().withTypeProvider<TypeBoxTypeProvider>()
app.post('/users', {
schema: { body: User, response: { 200: User } },
}, async (req) => {
// req.body is typed as User automatically
return req.body
})
スキーマがそのままOpenAPI応答仕様 + ランタイム検証 + 応答シリアライザ。1定義4仕事。
AIツール呼び出しでのTypeBox
OpenAI・Anthropic・Geminiの関数/ツール定義はJSON Schema。
const GetWeather = Type.Object({
city: Type.String(),
units: Type.Optional(Type.Union([Type.Literal('c'), Type.Literal('f')])),
})
const tool = {
type: 'function',
function: {
name: 'get_weather',
description: '指定された都市の現在の天気',
parameters: GetWeather, // already JSON Schema
},
}
zod-to-json-schema等の変換器を経ずに直接使える。変換で失う情報(format、description等)がない。
TypeBoxの強み
- JSON Schema標準そのまま — OpenAPI・AIツール呼び出し・AJVすべてに直結。
- AJVで最速ランタイム — ホットパス検証に最適。
- Fastify・Hono・Expressミドルウェア豊富。
- バンドル非常に小さい —
Type.*自体が軽い。
TypeBoxの弱み
- APIがやや冗長 —
Type.Object({ x: Type.String() })が長く感じる。 - チェーンの魅力はない —
z.string().email().min(5)の短さが恋しくなる。 - エコシステムがFastify寄り — Reactフォームライブラリのアダプタは少ない。
- 非同期検証は弱い — JSON Schema自体が同期中心。
7章 · Effect Schema — Effectエコシステムの検証ツール
EffectはScala・Haskellの影響を受けたフルスタックTS関数型フレームワーク。Effect Schemaはその中のデータ検証・変換モジュール。
「検証は双方向変換である。そしてすべてのエラーは型に入る。」
同じUserスキーマ。
import { Schema } from 'effect'
const User = Schema.Struct({
email: Schema.String.pipe(Schema.email()),
age: Schema.Number.pipe(Schema.int(), Schema.between(0, 150)),
name: Schema.NonEmptyString,
})
type User = Schema.Schema.Type<typeof User>
const decode = Schema.decodeUnknownSync(User)
const out = decode({ email: 'foo@example.com', age: 30, name: 'Foo' })
decodeUnknownSyncは同期検証。decodeUnknownまたはdecodeはEffect値を返す — Effectフルスタックの中で合成可能。
Effect Schemaの差別点
- 双方向 —
decode↔encode— JSON → ドメイン、ドメイン → JSON両方。Date・BigDecimal・Brand等のドメイン型を自然に扱える。 - 型付きエラー —
ParseErrorが型に入っているので、エラー処理漏れをコンパイラが捕える。 - Schema合成 —
Schema.compose、Schema.transform、Schema.filterで合成。 - JSON Schema組み込み —
JSONSchema.make(User)一行。
双方向変換の例
import { Schema } from 'effect'
// JSON stringで来るDateをドメインDateに
const DateFromString = Schema.transform(Schema.String, Schema.Date, {
decode: (s) => new Date(s),
encode: (d) => d.toISOString(),
})
const Event = Schema.Struct({
name: Schema.NonEmptyString,
at: DateFromString,
})
const decoded = Schema.decodeUnknownSync(Event)({ name: 'Launch', at: '2026-05-14T00:00:00Z' })
// ^ decoded.at is real Date
Effect Schemaの強み
- 双方向検証・変換の優雅さ — 他のライブラリで別途書く必要がある仕事が自然に解ける。
- 型付きエラーでエラー処理漏れを遮断。
- Effectフルスタックと合成 — HTTP・DB・キャッシュ・リトライまで1モデル。
- JSON Schema組み込み。
Effect Schemaの弱み
- Effectを使わないなら学習・バンドルコストが大きい — Effectコアが一緒に入る。
- チェーンに比べてコードが長く見える —
.pipe(Schema.email())に慣れるまでぎこちない。 - エコシステム — フォーム・tRPCアダプタは部分的。
- 学習曲線 — Effect本体の学習が必要。圏論・関数型親和が要る。
8章 · 同じスキーマ、5ライブラリ — User(email + age + name)
5つを横並びで見る。同じ意味のスキーマ。
8.1 Zod
import { z } from 'zod'
const User = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150),
name: z.string().min(1),
})
type User = z.infer<typeof User>
8.2 Valibot
import * as v from 'valibot'
const User = v.object({
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(150)),
name: v.pipe(v.string(), v.minLength(1)),
})
type User = v.InferOutput<typeof User>
8.3 ArkType
import { type } from 'arktype'
const User = type({
email: 'string.email',
age: '0 <= number.integer <= 150',
name: 'string > 0',
})
type User = typeof User.infer
8.4 TypeBox
import { Type, Static } from '@sinclair/typebox'
const User = Type.Object({
email: Type.String({ format: 'email' }),
age: Type.Integer({ minimum: 0, maximum: 150 }),
name: Type.String({ minLength: 1 }),
})
type User = Static<typeof User>
8.5 Effect Schema
import { Schema } from 'effect'
const User = Schema.Struct({
email: Schema.String.pipe(Schema.email()),
age: Schema.Number.pipe(Schema.int(), Schema.between(0, 150)),
name: Schema.NonEmptyString,
})
type User = Schema.Schema.Type<typeof User>
比較 — 同じスキーマ、違う哲学
| ライブラリ | 行数 | 文法スタイル | 推論呼び出し |
|---|---|---|---|
| Zod | 短い | チェーン | z.infer |
| Valibot | 中 | 関数合成(pipe) | v.InferOutput |
| ArkType | 最短 | TS DSL文字列 | typeof X.infer |
| TypeBox | 中 | Type ビルダー | Static |
| Effect Schema | 中 | .pipeチェーン | Schema.Schema.Type |
読みやすさはZod・ArkTypeが強く、バンドル・ツリーシェイキングはValibot・TypeBoxが強く、変換・エラー型まで担えばEffect Schemaが強い。
9章 · AIツール呼び出し時代 — JSON Schemaが強制される
2024〜2025の最大の流れ。すべての主要LLMがツール定義をJSON Schemaで受ける。
9.1 OpenAI function calling
const tools = [{
type: 'function',
function: {
name: 'get_weather',
description: 'Get the current weather in a given city',
parameters: {
type: 'object',
properties: {
city: { type: 'string' },
units: { type: 'string', enum: ['c', 'f'] },
},
required: ['city'],
},
},
}]
parametersは標準JSON Schema。オブジェクトを直接書くか、TSスキーマライブラリから変換する。
9.2 Anthropic tool use
const tools = [{
name: 'get_weather',
description: 'Get the current weather in a given city',
input_schema: {
type: 'object',
properties: {
city: { type: 'string' },
units: { type: 'string', enum: ['c', 'f'] },
},
required: ['city'],
},
}]
キー名が違うだけ(input_schema)。形は同じ。
9.3 ライブラリ別JSON Schema変換
- Zod —
@asteasolutions/zod-to-openapi、zod-to-json-schema、OpenAI SDKがzodFunctionヘルパで直接受けることも。Anthropic SDKもZod直接対応が進む。 - Valibot —
@valibot/to-json-schema公式パッケージ。 - ArkType —
User.toJsonSchema()組み込み。 - TypeBox — 変換不要。定義自体がJSON Schema。
- Effect Schema —
JSONSchema.make(User)組み込み。
9.4 変換時に失うもの
JSON SchemaはTS表現より限定的。変換時にしばしば失われるもの。
z.transform/v.transform等の双方向変換 — JSON Schemaは入力検証のみ。z.brandで作ったブランド型 — 単純なstring等に平坦化される。- 細かい
refine関数 — JSON Schemaに表現できない検証は消える。 - 再帰スキーマ —
$refの扱いはライブラリ・LLM側がうまく受けないことが多い。平坦化や深さ制限が安全。
9.5 OpenAI structured outputsとstrictモード
OpenAIが2024年後半に出したstructured outputsはJSON Schemaの一部制約(例: additionalProperties: false、必須フィールド、$ref非対応等)を強制する。TSライブラリの吐くJSON Schemaがその制約を破るとOpenAI側が拒否する。
実務のヒント。
- ツール呼び出し用スキーマは可能な限りシンプルに(平坦、
additionalProperties: false)。 descriptionフィールドを積極活用 — LLMが意味を理解する最良の手掛かり。- 再帰・
$refは避けるかLLM親和的に平坦化。 - 変換結果を一度sanity check — 変換後のJSON Schemaを直接見て意図通りか確認。
10章 · 7軸の詳細比較
10.1 バンドルサイズ
純粋なコアで小さなスキーマ一つを使う前提。
| ライブラリ | 小さい用途 | 大きい用途 | 備考 |
|---|---|---|---|
| Valibot | 最小(数百B) | 小 | ツリーシェイキングの頂点 |
| TypeBox | 非常に小さい | 小 | Type.*自体が軽い |
| ArkType | 小 | 中 | パーサーも一緒に入る |
| Zod 4 | 中(大幅減) | 中 | v4-miniはさらに小さい |
| Zod 3 | 大 | 大 | ツリーシェイキング弱い |
| Effect Schema | 大 | 大 | Effectコア含む |
| Yup | 中 | 中 | |
| Joi | 大 | 大 | ブラウザ親和性低い |
10.2 TypeScript推論品質
| ライブラリ | 推論品質 | 備考 |
|---|---|---|
| ArkType | 最高 | TS表現そのまま |
| Zod 4 | 非常に良い | z.infer広範 |
| Valibot | 非常に良い | InferOutput/InferInput |
| Effect Schema | 非常に良い | 双方向型まで |
| TypeBox | 良い | Static |
| Yup | 普通 | 推論は弱い |
| Joi | 弱い | 別途型作成必要 |
10.3 JSON Schemaエクスポート
| ライブラリ | 対応 | 方法 |
|---|---|---|
| TypeBox | ネイティブ | 定義自体 |
| ArkType | 組み込み | .toJsonSchema() |
| Effect Schema | 組み込み | JSONSchema.make() |
| Valibot | 公式外部 | @valibot/to-json-schema |
| Zod | 外部 | zod-to-json-schema、@asteasolutions/zod-to-openapi |
| Yup | 貧弱 | 非公式変換器 |
| Joi | なし | 手書き |
10.4 非同期検証
| ライブラリ | 対応 | パターン |
|---|---|---|
| Zod | 強い | z.string().refine(async ...) + parseAsync |
| Valibot | 強い | parseAsync/safeParseAsync |
| Effect Schema | 強い | Effect自体が非同期 |
| ArkType | 部分 | 同期中心 |
| TypeBox | 弱い | 同期検証中心 |
10.5 OpenAPIエクスポート
| ライブラリ | 対応 | ツール |
|---|---|---|
| TypeBox | 非常に良い | Fastify + Type Provider |
| ArkType | 良い | .toJsonSchema()直結 |
| Zod | 良い | @asteasolutions/zod-to-openapi、@hono/zod-openapi |
| Effect Schema | 良い | Effect HTTP·OpenAPIアダプタ |
| Valibot | 良い | @valibot/to-json-schema |
10.6 ランタイムコスト(ホットパス前提のおおよそ)
| ライブラリ | 検証速度 | 備考 |
|---|---|---|
| TypeBox + AJV(コンパイル) | 最速 | V8親和コンパイル |
| Valibot | 非常に速い | 関数合成が単純 |
| ArkType | 速い | コンパイル済みバリデータ |
| Zod 4 | 速い | 大幅改善 |
| Effect Schema | 中〜速 | Effectオーバーヘッド |
| Zod 3 | 普通 | 深いオブジェクトに弱い |
| Joi | 遅い | 重い古典API |
(正確な数値はケース次第。各ライブラリ公式ベンチマークと自分のワークロードで計測推奨。)
10.7 エコシステム(アダプタ・統合)
| ライブラリ | tRPC | RHF | OpenAI/Anthropic SDK | Fastify | Hono | Next.js |
|---|---|---|---|---|---|---|
| Zod | ファースト | ファースト | ファースト | 可 | 可 | ファースト |
| Valibot | 対応 | ファースト(@hookform/resolvers/valibot) | 外部変換 | 可 | 可 | 可 |
| ArkType | 対応 | 対応 | 外部変換 | 可 | 可 | 可 |
| TypeBox | 部分 | 部分 | 直接 | ファースト | ファースト(@hono/typebox-validator) | 可 |
| Effect Schema | 部分 | 部分 | 外部変換 | 可 | 可 | 可 |
11章 · Yup・Joi・Superstruct — 生きているが
11.1 Yup
Formik時代の標準。フォーム検証では今も使われるが新規採用は減る。Zod・Valibotに比べてTS推論が弱くバンドルが重い。
import * as yup from 'yup'
const User = yup.object({
email: yup.string().email().required(),
age: yup.number().integer().min(0).max(150).required(),
name: yup.string().min(1).required(),
})
11.2 Joi
Nodeバックエンドの古典標準。ブラウザ親和性が低い(バンドル大、依存が深い)。サーバー検証のレガシーコードベースに多く残っている。
const Joi = require('joi')
const User = Joi.object({
email: Joi.string().email().required(),
age: Joi.number().integer().min(0).max(150).required(),
name: Joi.string().min(1).required(),
})
11.3 Superstruct
小さく軽量な検証。io-tsより親しみやすいが、Zod・Valibotに比べてエコシステムは小さい。小規模プロジェクト・ライブラリ内部検証には依然良い選択。
import { object, string, number, refine } from 'superstruct'
const Email = refine(string(), 'email', (v) => /.+@.+/.test(v))
const User = object({
email: Email,
age: number(),
name: string(),
})
11.4 io-ts
伝統的関数型陣営。Effect Schemaがその座を急速に奪っている。新規コードでio-tsを自発的に始める例は減る。
12章 · Standard Schema — ライブラリ間の互換
2024年末〜2025年に登場したStandard Schema仕様は、検証ライブラリ群が合意した最小インターフェース。tRPC・Hono・React Hook Form等のツールが一つのアダプタでZod・Valibot・ArkTypeを受けられるようにする試み。
コアインターフェース(簡略化)。
interface StandardSchemaV1<Input = unknown, Output = Input> {
'~standard': {
version: 1
vendor: string
validate: (value: unknown) => StandardSchemaV1.Result<Output> | Promise<StandardSchemaV1.Result<Output>>
types?: { input: Input; output: Output }
}
}
Zod・Valibot・ArkType・Effect Schemaすべてがこのインターフェースを実装。結果 — ライブラリ選択のコストがさらに下がった。1コードベースに複数ライブラリが共存する、別ツールへ乗り換える際のコストが減った。
ただしStandard Schemaは最小共通でしかなく、ライブラリ固有機能(transform、refine、brand等)はアダプタ作者の仕事として残る。
13章 · 何をいつ選ぶか — 正直な結論
正解はいつもの通り**「状況による」**。ただパターンはある。
Zod 4を選ぶとき
- 最大のエコシステムが必要。tRPC・Next.js・React Hook Form・OpenAI/Anthropic SDKすべてがファースト。
- 学習資料・チュートリアル・回答プール(Stack Overflow)が最も厚い必要。
- バンドル1KBの差が問題にならないバックエンド・フルスタック。
- チームにZod経験者が既にいる。
Valibotを選ぶとき
- フロントエンド・エッジ優先。バンドルがそのままコスト。
- 関数型合成を好む。
- React Hook Form・React Router・Next.jsクライアントフォーム検証。
- 「Zodとほぼ同じ仕事をより小さく」 — 明確な動機。
ArkTypeを選ぶとき
- TS推論品質が最高でないと困る。
- TS表現をそのままスキーマにする発想が自然。
- JSON Schema組み込みが必要(外部パッケージ依存回避)。
- 自前のミニDSLに適応できるチーム。
TypeBoxを選ぶとき
- APIバックエンド — Fastify・Hono・Express + OpenAPI。
- AIツール呼び出し — JSON SchemaをLLMに直送。
- ホットパス検証 — AJVで最速ランタイム。
- スキーマ = OpenAPI = 検証 = シリアライザ。1定義4仕事。
Effect Schemaを選ぶとき
- チームが既にEffectフルスタックを行く途中。
- 双方向エンコーディング・変換がコア(Date・Brand・BigDecimal等)。
- 型付きエラーをコンパイラに強制させたい。
- 関数型・圏論親和的なチーム。
Yup・Joi・Superstructを選ぶとき
- レガシーコードベースの保守。
- Yup — Formik基盤のコード。
- Joi — Hapi.jsバックエンド。
- Superstruct — 依存最小の小規模ライブラリ。
アンチチェックリスト(避けるべきパターン)
- 1コードベースに検証ライブラリ3つ — Standard Schemaがあっても学習・デバッグコストは累積。
- 「ValibotがZodより小さいから乗り換えた」決定を計測なしで — 大きなスキーマでは差が縮む。
- TypeBoxですべてのフォーム検証 — フォームライブラリのアダプタが貧弱。Zod・Valibotが自然。
- AIツール呼び出しにZodをそのまま投げる — 変換を経由しつつ、変換後のJSON Schemaを一度点検。
z.refine/v.checkに変換できない検証を多用 — 変換後にその検証は消える。コア検証は変換可能な形に。
エピローグ — スキーマはAPI境界の真実
検証ライブラリの選択はどれだけ小さいか、どれだけ馴染みやすいか、どれだけ遠くまで連れて行けるかのトレードオフ。一方が優越するわけではない。ただ2026年5月の風景は明確だ。
- JSON Schema互換が1軍資格になった — AIツール呼び出しが強制した。Zodも外部パッケージで追いつき、TypeBox・ArkType・Effect Schemaは組み込み。
- バンドル競争はまだ終わっていない — Valibotが頂点を示し、Zod 4が大幅に追いついた。差は小さくなるが依然意味のある差。
- TS推論は標準資格 — どんなツールも推論が弱ければ新規採用で落ちる。
- Standard Schemaで乗り換えコストが下がった — もはや「一度決めたら一生」ではない。
- フルスタック1スキーマが次第に普遍 — 同じスキーマでサーバー検証・クライアントフォーム・ドキュメント・AIツール呼び出しまで。
意思決定チェックリスト
- API境界が最優先か? — TypeBoxまたはZod +
zod-to-openapi。 - フォーム・バンドル・エッジが最優先か? — ValibotまたはZod 4-mini。
- TS推論品質が最高でないと困るか? — ArkType。
- AIツール呼び出しJSON Schemaが中心か? — TypeBoxまたはArkType。
- Effectフルスタック中か? — Effect Schema。
- 学習・チュートリアル・エコシステムの厚さが重要? — Zod。
- 非同期検証が日常? — Zod・Valibot・Effect Schema。
- 双方向変換・ブランド型が必要? — Effect SchemaまたはZod transform。
アンチパターン
- 計測なしでライブラリ乗り換え — 決定は計測後。
- AIツールに変換結果を見ずに投げる —
additionalProperties・required漏れが頻発。 - JSON Schemaに表現できない
refineをコア検証にする — 変換時に消える。 - フォーム検証にTypeBox — RHFアダプタが弱い。Zod・Valibotが自然。
- 大きなオブジェクトに毎リクエスト
z.parseを繰り返す — ホットパスならコンパイル済みバリデータ(TypeBox + AJV)を検討。 - 1スキーマ2つの真実の源泉 — DBスキーマと検証スキーマが別の場所に定義されてずれる。
- エラーメッセージのカスタマイズを怠る — ライブラリデフォルトメッセージがユーザーに露出。
次回予告
候補: AIツール呼び出しJSON Schemaのデバッグ — OpenAI structured outputs・Anthropic tool useでよくあるミス集、Zod 4移行レポート — 5万行コードベース1ヶ月の作業、Valibot深掘り — ツリーシェイカーが実際に何を落とすか。
"検証はコードの境界である。境界が明確なコードだけが遠くまで行ける。"
— TypeScriptデータ検証 2026、終わり。
参考 / References
- Zod公式
- Zod GitHub — colinhacks/zod
- Zod v4 リリースノート
- Valibot公式
- Valibot GitHub — fabian-hiller/valibot
@valibot/to-json-schema- ArkType公式
- ArkType GitHub — arktypeio/arktype
- TypeBox README
- TypeBox + Fastify Type Provider
- Effect公式
- Effect Schema ドキュメント
- Standard Schema 公式
- Standard Schema GitHub
- AJV — JSON Schema検証器
zod-to-json-schema@asteasolutions/zod-to-openapi@hono/zod-openapi@hookform/resolvers- OpenAI function calling ドキュメント
- OpenAI structured outputs 発表
- Anthropic tool use ドキュメント
- Yup公式
- Joi公式
- Superstruct公式
- io-ts公式
- tRPC公式
- React Hook Form
현재 단락 (1/489)
2022年のTypeScriptで「ランタイム検証は何を使う?」と聞けば答えはほぼ一つだった。**Zod**。その前は**Joi**、**Yup**、または手書きの型ガード。