Zod란?
TypeScript-first schema validation with static type inference -Zod 공식문서
공식문서에 나와 있듯이 Zod는 정적 유형 추론을 통해 TypeScript 우선 스키마 유효성 검사를 제공하는 라이브러리입니다.
Typescript는 런타임에서 아무것도 보장하지 않기 때문에 타입 선언과 런타임 검증이 분리되어 생기는 문제를 해결하기 위해 만들어진 라이브러리입니다.
무엇을 해결해주나?
Typescript 타입은 런타임에 존재하지 않음
1type User = {
2 id: number;
3 email: string;
4};
5
6// user가 User 타입이라는 보장은 없음
7const user = JSON.parse(apiResponse);
다음 예시와 같이 API로부터 받아온 응답을 Typescript 타입으로 단순히 선언하는 것만으로는 런타임에서 해당 타입이 보장되지 않습니다. API 응답, 사용자 입력, 환경 변수 등 외부에서 들어오는 데이터는 항상 신뢰할 수 없기 때문에, 해당 데이터를 검증하는 과정이 필요합니다.
타입 선언과 검증 로직의 중복
1type User = {
2 id: number;
3 email: string;
4};
5
6// Type Guard 함수를 통해 user가 User 타입인지 검증
7function isUser(data: any): data is User {
8 return typeof data.id === "number" && typeof data.email === "string";
9}
다음과 같이 타입 선언과 검증 로직이 분리되어 있으면, 둘 중 하나만 변경될 경우 불일치가 발생합니다.
1type User = {
2 id: number;
3 email: string;
4 name: string; // name 필드가 추가됨
5};
6
7function isUser(data: any): data is User {
8 return (
9 typeof data.id === "number" && typeof data.email === "string"
10 // name 필드에 대한 검증이 누락됨
11 );
12}
이는 코드의 유지보수를 어렵게 만들고, 버그의 원인이 될 수 있습니다. Zod는 타입 선언과 검증 로직을 하나의 스키마로 통합하여 타입 + 런타임 검증을 동시에 해결합니다.
Zod는 어떤걸 해줄까?
✅ 런타임 검사
Zod를 통해 스키마를 정의해서 런타임에서 데이터를 검증할 수 있습니다.
1import { z } from "zod";
2
3const UserSchema = z.object({
4 id: z.number(),
5 email: z.string().email(),
6});
7
8// apiResponse가 User 타입인지 런타임에서 검증
9const parsedUser = UserSchema.parse(apiResponse);
parse 메서드는 데이터가 스키마에 맞지 않을 경우 에러를 던집니다. 이를 통해 서버 응답, 사용자 입력 등 "믿을 수 없는 데이터"를 안전하게 처리할 수 있습니다.
✅ 타입과 검증을 하나의 소스로 관리
1// 기존 방식
2type User = { ... }; // 타입 선언
3function isUser(data: any): data is User { ... } // 검증 로직
4
5// Zod
6const UserSchema = z.object({ ... }); // 스키마 정의
7type User = z.infer<typeof UserSchema>; // 스키마로부터 타입 추론
Zod를 사용하면 스키마 정의 하나로 타입과 검증 로직을 동시에 관리할 수 있습니다. 스키마가 변경되면 타입도 자동으로 업데이트되므로, 불일치 문제를 방지할 수 있습니다.
✅ 안전한 데이터 파싱
Zod는 safeParse 메서드를 제공하여, 검증 결과를 에러 대신 객체 형태로 반환할 수 있습니다.
1const result = UserSchema.safeParse(apiResponse);
2
3if (result.success) {
4 // 검증 성공, result.data를 안전하게 사용
5 const user = result.data;
6} else {
7 // 검증 실패, result.error에서 에러 정보 확인
8 console.error(result.error);
9}
다음 방식은 제어 흐름을 단순화하여 함수형/선언형 프로그래밍에 적합합니다.