타입스크립트(TypeScript)를 사용하면서 우리는 종종 착각에 빠지곤 합니다. "타입을 정의했으니, 런타임에서도 이 데이터는 안전할 거야"라고 말이죠. 하지만 타입스크립트의 타입 검사는 **빌드 시점(Compile Time)**에만 작동하며, 자바스크립트로 변환되는 순간 모두 사라집니다.
특히 외부 API에서 받아오는 데이터는 타입스크립트가 보호해 주지 못하는 '치외법권' 영역입니다. 백엔드에서 예고 없이 필드명을 바꾸거나 null을 내려주면, 우리 앱은 undefined 에러를 뿜으며 멈춰버립니다. 오늘은 이러한 '런타임 불확실성'을 제거해 주는 강력한 스키마 검증 라이브러리, Zod를 소개합니다.
1. 타입스크립트의 한계: 정적 타입 vs 동적 데이터
타입스크립트는 '기대하는 데이터의 형태'를 정의할 뿐, 실제 들어온 데이터가 그 형태인지 확인하지는 않습니다.
interface User {
id: number;
name: string;
}
// API 응답이 { id: "1", name: null }로 와도 TS는 에러를 잡지 못함
const user: User = await fetch('/api/user').then(res => res.json());
console.log(user.name.toUpperCase()); // 런타임 에러 발생!
이처럼 외부 데이터에 의존하는 프런트엔드 환경에서는 **런타임에서의 데이터 검증(Runtime Validation)**이 필수적입니다.
2. Zod란 무엇인가?
Zod는 'TypeScript-first' 스키마 선언 및 유효성 검사 라이브러리입니다. 단순히 데이터가 맞는지 확인하는 것을 넘어, 검증된 데이터로부터 타입스크립트 타입을 자동으로 추출해 주는 기능을 제공합니다.
2.1 Zod 스키마 정의하기
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(), // 이메일 형식까지 검증 가능
role: z.enum(['admin', 'user']),
});
// 스키마로부터 타입 추출 (중복 정의 필요 없음!)
type User = z.infer<typeof UserSchema>;
3. 실전 활용: API 응답 안전하게 받기
Zod의 parse 메서드를 사용하면 데이터가 스키마와 일치하지 않을 때 즉시 에러를 발생시켜, 잘못된 데이터가 앱 내부로 흘러 들어오는 것을 원천 차단합니다.
3.1 안전한 패칭 로직
async function fetchUser(id: number) {
const response = await fetch(`/api/user/${id}`);
const rawData = await response.json();
// 데이터 검증 시작
const result = UserSchema.safeParse(rawData);
if (!result.success) {
// 유효성 검사 실패 시 처리 (로깅, 에러 바운더리 등)
console.error("데이터 형식이 올바르지 않습니다:", result.error.format());
throw new Error("Invalid Data");
}
return result.data; // 여기서 반환되는 데이터는 완벽하게 타입이 보장됨
}
4. Zod의 강력한 기능들
4.1 기본값 및 변환 (Transform)
데이터를 검증함과 동시에 원하는 형태로 가공할 수도 있습니다.
- default: 데이터가 없을 때 기본값 부여.
- transform: 문자열로 온 날짜 데이터를 Date 객체로 자동 변환.
const ProductSchema = z.object({
price: z.number(),
createdAt: z.string().transform((str) => new Date(str)),
});
4.2 조건부 검증
"나이가 19세 이상일 때만 성인 인증 여부가 필수" 같은 복잡한 로직도. refine()을 통해 구현할 수 있습니다.
5. React Hook Form과의 찰떡궁합
프론트엔드에서 Zod가 가장 많이 쓰이는 곳 중 하나가 바로 폼(Form) 검증입니다. react-hook-form의 zodResolver를 사용하면 복잡한 유효성 검사 로직을 선언적으로 관리할 수 있습니다.
const { register, handleSubmit } = useForm({
resolver: zodResolver(SignUpSchema),
});
사용자가 입력을 마치는 순간 Zod 스키마에 따라 즉시 검증이 이뤄지며, 타입 안전성까지 챙길 수 있어 실무에서 매우 선호되는 조합입니다.
'개발' 카테고리의 다른 글
| [TS] 제네릭(Generic)을 활용한 재사용 가능한 고차 컴포넌트(HOC) 설계 (0) | 2026.04.27 |
|---|---|
| [TS] Utility Types 정복하기: Pick, Omit, Partial로 중복 없는 타입 정의 (0) | 2026.04.27 |
| [TS] any 대신 unknown을 써야 하는 이유와 타입 가드 활용법 (0) | 2026.04.27 |
| [Architecture] 프론트엔드 클린 아키텍처: 도메인 로직과 UI 컴포넌트 분리하기 (0) | 2026.04.27 |
| [React] 선언적 프로그래밍의 정수: Suspense와 ErrorBoundary로 우아한 UI 만들기 (0) | 2026.04.27 |