Zod란 무엇인가: TypeScript에서 런타임 검증과 타입 안정성을 동시에 해결하는 방법
TypeScript 프로젝트를 하다 보면 반드시 마주치는 문제가 있다.
바로 “타입은 있는데, 데이터는 믿을 수 없다”는 것이다.
TypeScript는 컴파일 타임에는 강력하지만,
런타임에 들어오는 데이터에 대해서는 아무런 보장을 해주지 않는다.
API 요청 데이터
사용자 입력(Form)
환경 변수 (
process.env)외부 JSON / 설정 파일
이 모든 것은 타입 시스템 바깥에서 들어온다.
이 문제를 해결하기 위해 등장한 라이브러리 중,
최근 사실상 표준처럼 사용되고 있는 것이 Zod다.
1. Zod란 무엇인가?
Zod는 TypeScript 환경에서 사용하는 런타임 스키마 검증 라이브러리다.
하지만 단순히 “validation 라이브러리”라고 부르기엔 범위가 훨씬 넓다.
Zod의 핵심 역할은 다음 두 가지다.
런타임에서 실제 데이터를 검증한다
그 검증 규칙으로부터 TypeScript 타입을 자동으로 만들어낸다
즉, Zod는
👉 검증과 타입 정의를 하나의 선언으로 묶는다.
2. 기존 방식의 문제점
Zod 없이 TypeScript로 개발할 때의 전형적인 패턴은 이렇다.
type User = {
id: number;
name: string;
};
그리고 어딘가에서:
function validateUser(data: any): User {
// 직접 작성한 검증 로직
}
이 방식의 문제는 명확하다.
타입과 검증 로직이 분리되어 있다
둘 중 하나만 수정되기 쉽다
시간이 지나면 타입과 실제 데이터가 어긋난다
실무에서 버그가 생기는 지점도 대부분 여기다.
3. Zod의 핵심 아이디어: 스키마를 중심에 둔다
Zod에서는 타입을 먼저 정의하지 않는다.
대신 스키마(schema) 를 먼저 정의한다.
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
});
이 한 줄의 스키마는 동시에 다음 역할을 한다.
런타임에서 데이터 검증
TypeScript 타입의 근원 (Single Source of Truth)
그리고 이 스키마를 통해:
type User = z.infer<typeof UserSchema>;
타입을 자동으로 얻는다.
4. Zod 스키마는 어떻게 동작하는가 (개념)
Zod 스키마는 단순한 설정 객체가 아니다.
각 스키마는 내부적으로 다음 정보를 함께 가진다.
입력값을 어떻게 검증할 것인가
검증이 끝난 후 출력 타입은 무엇인가
예를 들어:
z.string(); // string
z.string().optional(); // string | undefined
z.string().transform(Number); // number
검증 규칙이 추가되거나 변환이 일어나도,
Zod는 그 결과 타입을 계속 추적한다.
이 덕분에 런타임 동작과 타입 정보가 서로 어긋나지 않는다.
5. 실제 사용에서 Zod가 강력한 이유
1) 외부 입력에 대한 신뢰 확보
const result = UserSchema.safeParse(data);
if (!result.success) {
// 에러 처리
}
이 시점 이후의 result.data는:
런타임에서 검증된 값이고
TypeScript 타입도 정확히 보장된다
2) 중복 제거
타입 정의 ❌
검증 로직 ❌
➡️ 스키마 하나로 끝
3) 프론트엔드 / 백엔드 모두에서 사용 가능
API request / response
Form validation
환경 변수 검증
설정 파일 파싱
Zod는 계층을 가리지 않고 같은 패턴으로 사용된다.
6. Zod가 “TypeScript-first”라고 불리는 이유
Zod는 단순히 TypeScript를 “지원”하는 라이브러리가 아니다.
처음부터:
TypeScript 타입 추론을 전제로 API가 설계되었고
사용자가 타입을 직접 작성하지 않아도
정확한 타입이 자연스럽게 따라오도록 만들어졌다
그래서 Zod는 흔히 TypeScript-first 라이브러리라고 불린다.
7. z.infer는 무엇을 하는가
type User = z.infer<typeof UserSchema>;
z.infer는 런타임에 실행되는 함수가 아니다.
TypeScript 타입 시스템에서만 동작하는 타입 유틸리티다.
Zod의 모든 스키마는 내부적으로 다음과 같은 타입 정보를 가지고 있다.
이 스키마가 검증을 통과하면
어떤 형태의 값이 결과로 나오는지
즉, 각 스키마에는 이미 “출력 타입”이 타입 레벨로 저장되어 있다.
z.infer의 역할은 단순하다.
Zod 스키마 타입 안에 숨겨진 출력 타입을
TypeScript가 사용할 수 있는 타입으로 꺼내준다.
그래서 다음 두 코드는 개념적으로 같다.
type User = z.infer<typeof UserSchema>;
type User = (typeof UserSchema)["_output"];
중요한 점은,
타입을 사람이 직접 작성하지 않고
스키마 선언 결과를 TypeScript가 계산하도록 맡긴다는 것이다.
이 덕분에 스키마가 바뀌면 타입도 항상 함께 바뀌며,
런타임 검증 로직과 타입 정의가 어긋날 일이 없다.
8. 정리
Zod는 단순한 validation 라이브러리가 아니다.
런타임 검증을 제공하면서
TypeScript의 타입 시스템과 깊게 결합하고
타입 정의와 검증 로직을 하나로 통합한다
그래서 Zod는 이렇게 정의할 수 있다.
Zod는
TypeScript 환경에서 “믿을 수 있는 데이터”를 만들기 위한
스키마 중심 설계 도구다.
🧾 작성 참고
이 글은 ChatGPT의 도움을 받아 내용을 정리하였습니다.