Files
2nd/10_Wiki/Topics/Coding/TS_Schema_Validation_Comparison.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

4.5 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
ts-schema-validation-comparison Schema 검증 비교 — Zod / Valibot / Effect Schema / ArkType Coding draft B conceptual 2026-05-09 2026-05-09
typescript
validation
zod
vibe-coding
language applicable_to
TS
Backend
Frontend
Zod
Valibot
Effect Schema
ArkType
Yup
runtime validation
schema

Schema Validation 비교

Runtime 검증 + TS infer = 표준. Zod = 가장 일반, Valibot = 작은 bundle, ArkType = 빠르고 syntax 신선, Effect Schema = Effect 사용자.

📖 핵심 개념

  • 검증: unknown → typed parse / fail.
  • Infer: schema → TS type.
  • Refinement: 추가 조건 (email, regex).
  • Transform: parse 시 변환.

💻 코드 패턴

Zod (de-facto 표준)

import { z } from 'zod';

const User = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  age: z.number().int().positive().optional(),
  role: z.enum(['admin', 'user']).default('user'),
  tags: z.array(z.string()).default([]),
});

type User = z.infer<typeof User>;

const parsed = User.parse(input);    // throws ZodError
const safe = User.safeParse(input);  // { success, data | error }
// transform
const Trimmed = z.string().transform(s => s.trim());

// refine
const StrongPw = z.string().refine(s => s.length >= 8 && /[0-9]/.test(s));

// discriminated union
const Action = z.discriminatedUnion('type', [
  z.object({ type: z.literal('a'), x: z.number() }),
  z.object({ type: z.literal('b'), y: z.string() }),
]);

Valibot (작은 bundle, tree-shakable)

import * as v from 'valibot';

const User = v.object({
  id: v.pipe(v.string(), v.uuid()),
  email: v.pipe(v.string(), v.email()),
  age: v.optional(v.pipe(v.number(), v.integer(), v.minValue(0))),
});

type User = v.InferOutput<typeof User>;

const parsed = v.parse(User, input);

→ Bundle: zod ~13KB vs valibot ~2KB.

ArkType (빠른 + syntax)

import { type } from 'arktype';

const User = type({
  id: 'string',
  email: 'email',
  age: 'number > 0?',
  role: '"admin" | "user"',
});

type User = typeof User.infer;

const out = User(input);
if (out instanceof type.errors) console.log(out.summary);
else console.log(out);

→ TS-template-literal 기반 — runtime 빠름, dev 시 type 직접 추적.

Effect Schema

import { Schema } from 'effect';

const User = Schema.Struct({
  id: Schema.String.pipe(Schema.uuid()),
  email: Schema.String.pipe(Schema.email()),
  age: Schema.Number.pipe(Schema.positive()),
});

const decoded = Schema.decodeUnknownSync(User)(input);

→ Effect 와 통합.

공통 패턴

Form (RHF)

import { zodResolver } from '@hookform/resolvers/zod';
useForm({ resolver: zodResolver(schema) });

API (Hono)

import { zValidator } from '@hono/zod-validator';

app.post('/users', zValidator('json', User), (c) => {
  const data = c.req.valid('json'); // typed
});

환경변수

const Env = z.object({
  DATABASE_URL: z.string().url(),
  PORT: z.coerce.number().default(3000),
  NODE_ENV: z.enum(['dev', 'prod', 'test']),
});

export const env = Env.parse(process.env);

LLM structured output

const Recipe = z.object({...});
zodResponseFormat(Recipe, 'recipe'); // OpenAI
zodToJsonSchema(Recipe);              // Anthropic

Migration zod → valibot

// 비슷한 API — 직접 변경
z.object({ name: z.string() })
v.object({ name: v.string() })

z.string().email()
v.pipe(v.string(), v.email())

🤔 의사결정 기준

상황 추천
일반 (백 + 프론트) Zod
Frontend bundle critical Valibot
성능 critical (validation hot path) ArkType
Effect 사용 중 Effect Schema
학습 / 안정성 Zod
Shared backend + frontend Zod (가장 호환)

안티패턴

  • 검증 없이 unknown 그대로 사용: 런타임 crash.
  • Zod schema 가 거대 (50+ 필드): 분리 + compose.
  • Refinement 안에 외부 fetch: synchronous expected. transform.
  • .passthrough() 디폴트: extra 키 안 차단. strict.
  • Type 직접 정의 + schema 따로: drift. infer.
  • Form schema = API schema 직접: 다를 수 있음 — 분리.
  • zod + 큰 bundle 신경 X: SSR 만 / API 만 사용.

🤖 LLM 활용 힌트

  • Zod 가 안전 디폴트.
  • Bundle 작아야 = Valibot.
  • AI structured output = Zod (OpenAI helper).

🔗 관련 문서