Zod v4.6.7 内部アーキテクチャ概要
Zod v4(v4.6.7、packages/zod/src/ 配下の 112個のTypeScriptモジュール・16,733行)は、TypeScript標準スキーマ検証ライブラリの内部設計をゼロから再構築したメジャーアーキテクチャ刷新版です。従来の単一ES6クラス継承階層を廃止し、メソッドを持たないコアエンジン(v4/core)、2種類のユーザー向けファサード(v4/classic と v4/mini)、および遅延読み込み対応の49以上の多言語ロケール(v4/locales)の4層に分離されています。
Source Code
from drawlib.canvas import save, setup
from drawlib.icons import phosphor
from drawlib.lines import line
from drawlib.smartarts import CardList, Panel
from drawlib.styles import Styles
from drawlib.text import text
setup(width=156, height=106)
text(
(78, 101.5),
"Zod v4.6.7 システムアーキテクチャ — 4層内部レイヤ構造",
style=Styles.DarkBold.patch(text_size=13.5),
)
text(
(78, 97.5),
"エントリポイント・2系統ファサード・多言語ロケール・コアエンジンで構成される全112モジュール(16,733 LOC)",
style=Styles.Muted.patch(text_size=10.0),
)
# Layer 1: Subpath Entrypoints
p_entry = Panel(
"Layer 1: パッケージエントリポイント (packages/zod/src/* & package.json exports)",
style=Styles.Neutral,
header_style=Styles.Secondary,
text_style=Styles.WhiteBold.patch(text_size=10.5),
header_height=6.0,
)
p_entry.draw(xy=(6, 76), width=144, height=18)
entry_list = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="horizontal",
spacing=2.0,
)
entry_list.add("zod / zod/v4", description="v4/classic ファサード", style=Styles.PrimaryNeutral)
entry_list.add("zod/mini", description="v4/mini 軽量ファサード", style=Styles.PrimaryNeutral)
entry_list.add("zod/v4/core", description="コアエンジン直参照")
entry_list.add("zod/compile", description="AOT postProcessor")
entry_list.add("zod/locales", description="49+ 言語エラーマップ")
entry_list.draw(xy=(9, 77.5), width=138, height=9.0)
# Layer 2A: v4/classic
p_classic = Panel(
"Layer 2A: v4/classic (12モジュール)",
style=Styles.PrimaryNeutral,
header_style=Styles.Primary,
text_style=Styles.WhiteBold.patch(text_size=10.5),
icon=phosphor.cube,
icon_style=Styles.White,
header_height=6.0,
)
p_classic.draw(xy=(6, 46), width=58, height=23)
classic_cards = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="vertical",
spacing=1.5,
)
classic_cards.add("ZodType & 45+ スキーマ", description="メソッドチェーン (.min, .optional, .pipe)")
classic_cards.add("fromJSONSchema & 互換層", description="v3互換エイリアス + 既定 en() ロケール")
classic_cards.draw(xy=(8.5, 47.5), width=53, height=14.0)
# Layer 2B: v4/mini
p_mini = Panel(
"Layer 2B: v4/mini (9モジュール)",
style=Styles.PrimaryNeutral,
header_style=Styles.Primary,
text_style=Styles.WhiteBold.patch(text_size=10.5),
icon=phosphor.feather,
icon_style=Styles.White,
header_height=6.0,
)
p_mini.draw(xy=(67, 46), width=47, height=23)
mini_cards = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="vertical",
spacing=1.5,
)
mini_cards.add("ZodMiniType ファサード", description="メソッド省略 (~85% バンドル削減)")
mini_cards.add("関数型コンビネータ", description="z.check(z.minLength(5))")
mini_cards.draw(xy=(69.5, 47.5), width=42, height=14.0)
# Layer 3: v4/locales
p_locales = Panel(
"Layer 3: v4/locales",
style=Styles.Neutral,
header_style=Styles.Secondary,
text_style=Styles.WhiteBold.patch(text_size=10.5),
icon=phosphor.translate,
icon_style=Styles.White,
header_height=6.0,
)
p_locales.draw(xy=(117, 46), width=33, height=23)
locale_cards = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="vertical",
spacing=1.5,
)
locale_cards.add("49+ 言語エラーマップ", description="en.ts, ja.ts, es.ts...")
locale_cards.add("遅延メッセージ生成", description="globalConfig.localeError")
locale_cards.draw(xy=(119.0, 47.5), width=29, height=14.0)
# Layer 4: v4/core
p_core = Panel(
"Layer 4: v4/core — 共通ランタイム・トレイト・JITコンパイラ基盤 (21モジュール・上位依存ゼロ)",
style=Styles.Neutral,
header_style=Styles.PrimaryFlat,
text_style=Styles.WhiteBold.patch(text_size=10.5),
icon=phosphor.cpu,
icon_style=Styles.White,
header_height=6.0,
)
p_core.draw(xy=(6, 5), width=144, height=34)
core_row1 = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="horizontal",
spacing=2.5,
)
core_row1.add(
"core.ts & util.ts",
description="$constructor トレイト・clone()・defineLazy()",
style=Styles.PrimaryFlat,
text_style=Styles.WhiteBold.patch(text_size=10.0),
description_style=Styles.White.patch(text_size=9.5),
)
core_row1.add(
"schemas.ts & api.ts (5,227行)",
description="core.$ZodType / Object / Pipe / Codec",
style=Styles.PrimaryNeutral,
)
core_row1.add(
"checks.ts & regexes.ts",
description="$ZodCheck 検証ルール & 正規表現",
)
core_row1.draw(xy=(9, 21.0), width=138, height=10.0)
core_row2 = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=10.0),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="horizontal",
spacing=2.5,
)
core_row2.add(
"parse.ts & errors.ts",
description="ParsePayload・同期/非同期・遅延 $ZodError",
)
core_row2.add(
"doc.ts & compile.ts",
description="Doc ビルダ・$ZodObjectJIT・compile()",
style=Styles.AccentFlat,
text_style=Styles.WhiteBold.patch(text_size=10.0),
description_style=Styles.White.patch(text_size=9.5),
)
core_row2.add(
"registries.ts & to-json-schema.ts",
description="WeakMap $ZodRegistry & JSON Schema 生成",
)
core_row2.draw(xy=(9, 8.0), width=138, height=10.0)
# Downward dependency arrows (orthogonal gaps = 7.0 units)
line((35, 76), (35, 69), arrow_head="->", style=Styles.PrimaryBold)
line((90.5, 76), (90.5, 69), arrow_head="->", style=Styles.PrimaryBold)
line((133.5, 76), (133.5, 69), arrow_head="->", style=Styles.SecondaryBold)
line((35, 46), (35, 39), arrow_head="->", style=Styles.PrimaryBold)
text((46, 42.5), "import * as core", style=Styles.Primary.patch(text_size=9.5))
line((90.5, 46), (90.5, 39), arrow_head="->", style=Styles.PrimaryBold)
text((101.5, 42.5), "import * as core", style=Styles.Primary.patch(text_size=9.5))
line((133.5, 46), (133.5, 39), arrow_head="->", style=Styles.SecondaryBold)
save()
1. なぜ Zod v4 は再設計されたのか
Zod v3 は数百万のTypeScriptプロジェクトで採用されましたが、大規模化に伴い以下の3つの構造的ボトルネックが顕在化していました。
- Tree-Shaking不可能なプロトタイプメソッド群: Zod v3の
ZodTypeやZodStringは、数十個のメソッド(.email(),.url(),.uuid(),.optional(),.nullable(),.transform()等)を単一ES6クラスのプロトタイプに保持していました。そのためz.string()を1つインポートするだけで、未使用のフォーマット検証器やラッパークラスまでバンドルに引き込まれていました。 tscにおける深いジェネリッククラス継承: Zod v3はZodType<Output, Def, Input>という多引数ジェネリッククラスで型状態を表現していたため、.optional()や.extend()を連鎖させるたびにTypeScriptコンパイラが膨大なメソッドオーバーロードと変位(variance)を再評価していました。- パース時の積極的なエラー・コンテキスト割り当て: Zod v3は各検証ステップで重い
ParseContextフレームやパス配列、ZodErrorインスタンスを即時生成しており、ユニオン型の分岐失敗時にも不要なヒープ割り当てが発生していました。
Zod v4(v4.6.7)は、以下の4つのアーキテクチャ刷新によってこれらすべての課題を解決しています。
| 設計軸 | Zod v3 アーキテクチャ | Zod v4 (v4.6.7) アーキテクチャ |
主要ソースモジュール |
|---|---|---|---|
| パッケージ構造 | 単一モノリシック構成 | 3層分離: v4/core 基盤 + v4/classic & v4/mini ファサード |
v4/core/, v4/classic/, v4/mini/ |
| クラス・トレイトモデル | ES6 class extends ZodType |
$constructor トレイト合成: _.init(inst, def) + traits: Set<string> |
v4/core/core.ts, v4/core/util.ts |
| 型レベル推論 | ZodType<Output, Def, Input> |
ファントム _zod プロパティバッグ: T["_zod"]["output"] & T["_zod"]["input"] |
v4/core/core.ts, v4/core/schemas.ts |
| 検証ランタイム | 重い ParseInput / 同期・非同期分離 |
最小 ParsePayload: { value, issues } + MaybeAsync & JIT Doc |
v4/core/parse.ts, v4/core/compile.ts |
| メタデータ & JSON Schema | _def.description のみ |
WeakMap レジストリ分離: $ZodRegistry + 標準内蔵 toJSONSchema() |
v4/core/registries.ts, v4/core/to-json-schema.ts |
2. エンドツーエンド実行ライフサイクル
Zod v4におけるすべてのスキーマは、トレイト初期化からランタイム検証・JITコンパイル、メタデータ登録、そしてJSON Schema出力に至る4つの一貫したサブシステムを通過します。
Source Code
from drawlib.canvas import save, setup
from drawlib.lines import line
from drawlib.smartarts import CardList, ChevronProcess, Panel
from drawlib.styles import Styles
from drawlib.text import text
setup(width=156, height=88)
text(
(78, 83.5),
"Zod v4 コアサブシステムを横断するエンドツーエンド実行ライフサイクル",
style=Styles.DarkBold.patch(text_size=13.5),
)
# Top Chevron Process
flow = ChevronProcess(
style=Styles.PrimaryNeutral,
text_style=Styles.DarkBold.patch(text_size=10.5),
description_style=Styles.Dark.patch(text_size=9.5),
corner_angle=60.0,
spacing=1.5,
flat_left_end=True,
)
flow.add(
"1. $constructor 構築",
description="core.ts / schemas.ts",
style=Styles.PrimaryFlat,
text_style=Styles.WhiteBold.patch(text_size=10.5),
description_style=Styles.White.patch(text_size=9.5),
)
flow.add("2. 検証 & JIT 実行", description="parse.ts / compile.ts")
flow.add("3. $ZodRegistry 管理", description="registries.ts")
flow.add(
"4. JSON Schema 合成",
description="to-json-schema.ts",
style=Styles.AccentFlat,
text_style=Styles.WhiteBold.patch(text_size=10.5),
description_style=Styles.White.patch(text_size=9.5),
)
flow.draw(xy=(6, 65), width=144, height=13)
# 4 Detailed Stage Panels below
stages = [
(
6,
"1. トレイト初期化",
Styles.Primary,
[
("new Internals(def)", "インオブジェクト _zod 領域"),
("_.init(inst, def)", "トレイト階層の多段合成"),
("deferred[] & onattach", "_zod.run と bag の結線"),
("clone(inst, newDef)", "不変チェイニング生成"),
],
),
(
42.5,
"2. 検証 & JIT 実行",
Styles.Secondary,
[
("ParsePayload { value }", "正常系の割り当て最小化"),
("Fastpass / Doc.compile()", "new Function() JIT 関数"),
("MaybeAsync ハイブリッド", "Promise時のみ非同期遷移"),
("finalizeIssue() + ロケール", "遅延 $ZodError ゲッター"),
],
),
(
79,
"3. WeakMap 管理",
Styles.Secondary,
[
("globalRegistry", "globalThis による単一化"),
("_map: WeakMap<Schema>", "GC安全なメタデータ保持"),
("_idmap: Map<id, Schema>", "名前付き $defs 逆引き"),
("親スキーマからの継承", "_zod.parent チェーン走査"),
],
),
(
115.5,
"4. JSON Schema",
Styles.Primary,
[
("initializeContext()", "Draft-04 / 07 / 2020-12"),
("processSchema() 走査", "型別プロセッサテーブル実行"),
("循環参照・再利用検出", "seen Map カウントと $ref"),
("extractDefs & finalize", "標準 JSON Schema 出力"),
],
),
]
for x0, title, hdr_style, items in stages:
p = Panel(
title,
style=Styles.Neutral,
header_style=hdr_style,
text_style=Styles.WhiteBold.patch(text_size=10.0),
header_height=6.0,
)
p.draw(xy=(x0, 6), width=34.5, height=51)
cl = CardList(
style=Styles.White,
text_style=Styles.DarkBold.patch(text_size=9.5),
description_style=Styles.Muted.patch(text_size=9.5),
badge_shape="none",
direction="vertical",
spacing=1.5,
)
for item_title, item_desc in items:
cl.add(item_title, description=item_desc)
cl.draw(xy=(x0 + 2.0, 8.0), width=30.5, height=41.0)
line((x0 + 17.25, 65), (x0 + 17.25, 57), arrow_head="->", style=Styles.PrimaryBold)
save()
3. コアエンジニアリングの3大支柱
3.1 _zod 内部プロパティバッグによる tsc 型推論の 10倍+ 高速化
packages/zod/src/v4/core/schemas.ts において、基底インターフェース $ZodType はすべてのランタイム内部状態と型推論情報を単一の非列挙プロパティ _zod に集約しています。
// packages/zod/src/v4/core/schemas.ts
export interface $ZodType<
O = unknown,
I = unknown,
Internals extends $ZodTypeInternals<O, I> = $ZodTypeInternals<O, I>,
> {
_zod: Internals;
"~standard": $ZodStandardSchema<this>;
}
さらに packages/zod/src/v4/core/core.ts では、z.input<T> と z.output<T>(および z.infer<T>)が _zod に対する単純なインデックスアクセス条件型として定義されています。
// packages/zod/src/v4/core/core.ts
export type input<T> = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown;
export type output<T> = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown;
export type { output as infer };
変位(variance)や型計算を Internals extends $ZodTypeInternals<O, I> 内に閉じ込めることで、TypeScriptコンパイラはメソッドチェーンのたびに数十個のジェネリックメソッドシグネチャを再評価する必要がなくなり、構造的型チェックのキャッシュ効率が飛躍的に向上しています。
3.2 V8 インラインスロット維持とプロトタイプ遅延実体化
core.ts および util.ts の随所には、V8エンジンのオブジェクト表現(Hidden Class / Map)を意識した最適化が施されています。
- 共有
_zodプロトタイプ (zodProto):$constructor(packages/zod/src/v4/core/core.ts)はコンストラクタごとに専用のInternals関数とzodProtoを生成します。pattern,values,propValues,optin,optoutといった遅延評価プロパティは、各インスタンスに直接Object.definePropertyで定義するのではなく、defineLazyInternal()(util.ts)によってzodProto上に1度だけ定義されます。これによりインスタンスがV8の辞書モード(Dictionary Mode: 1オブジェクトあたり約360 B)へ降格するのを防ぎ、インラインスロット(約100 B)を維持します。 - プロトタイプメソッドの遅延バインド (
members&defineBound):v4/classicやv4/miniのメソッドはプロトタイプ上に配置され、メソッドが取り出された(デタッチされた)初回アクセス時のみインスタンス自身のデータプロパティとして束縛(bind)されます(util.ts:L1133-1187)。 - スタックトレース取得を抑止したエラー生成 (
newError): V8でnew Error()を呼ぶ際、スタックフレームのキャプチャが失敗パス全体の処理時間を支配します。core.tsのnewError()は一時的にError.stackTraceLimit = 0に設定してインスタンスを生成し、parse.ts側でError.captureStackTrace(e, callee)を呼ぶことで呼び出し元基準のクリーンなスタックトレースを1度だけ構築します。
3.3 globalThis シングルトンによる Dual-Package Hazard 回避
同一プロセス内でESM(import)とCJS(require)の両方からパッケージが読み込まれる「Dual-Package Hazard」に対処するため、Zod v4は状態を持つ2つのシングルトンを globalThis に直接保持します。
globalThis.__zod_globalConfig(packages/zod/src/v4/core/core.ts:L224):customError,localeError,jitless,memoizer,postProcessorをCJS/ESM横断で共有します。globalThis.__zod_globalRegistry(packages/zod/src/v4/core/registries.ts:L104):z.globalRegistry(.describe()や.meta()の保存先)がバンドル境界を越えて一貫して解決されることを保証します。
4. アーキテクチャ解説チャプター一覧
本ポータルでは、全6章にわたって Zod v4.6.7 のソースコードを徹底解剖します。
- 1. 3層パッケージトポロジ (
v4/core,classic,mini) 全112モジュールの有向非巡回グラフ(DAG)、下位方向のみのインポート制約、zshyによるESM/CJSデュアルビルド、@zod/source条件付きエクスポート、zod/miniが約85%のバンドルサイズ削減を実現する仕組みを解説します。 - 2.
$constructorトレイトシステムと不変性core.tsの$constructor()実装、複数トレイト合成($ZodStringFormat+$ZodCheck)、カスタムSymbol.hasInstance、clone()、defineLazyInternal()、およびV8隠しクラス最適化を解説します。 - 3.
ParsePayload・ハイブリッド同期/非同期実行・検証エンジンparse.tsの_parse/_encode/_decode、双方向コンテキストParseContextInternal(direction: "forward" | "backward")、aborted()の継続制御、$ZodObjectのプロパティ検証ファストパス、$ZodCheckチェーンを解説します。 - 4.
Docコードビルダと JIT / AOT スキーマコンパイラdoc.ts(クロージャコード生成ビルダ)、$ZodObjectJITによるオブジェクト高速パス、およびcompile.ts(z.compile()とzod/compileAOTポストプロセッサ)の内部構造を解説します。 - 5. WeakMapメタデータレジストリと JSON Schema 合成
$ZodRegistry(WeakMap+$replace<Meta, S>型置換)、to-json-schema.ts、json-schema-processors.ts、循環参照の$defs抽出、およびfrom-json-schema.tsを解説します。 - 6. 型レベル推論設計と 49言語ロケールエンジン
_zodファントム変位設計、toZod<T>()のキー単位型不一致診断、$ZodRawIssueのエラーメッセージ解決優先順位、およびv4/locales/の多言語エラーマップ群を解説します。