Files
2nd/10_Wiki/Topic_Programming/Coding/TS_Schema_Validation_Comparison.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +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).

🔗 관련 문서