본문 바로가기

Library

Zod

Zod

  • TypeScript 기반의 스키마 선언 및 유효성 검사 라이브러리
  • TypeScript 의 타입 시스템과 완벽하게 통합되어 런타임에서 데이터 유효성을 검사할 수 있음
  • 타입 안정성, 간결한 구문, 비동기 유효성 검사, 확장성, 유연한 검증 로직 구성을 제공
 

GitHub - colinhacks/zod: TypeScript-first schema validation with static type inference

TypeScript-first schema validation with static type inference - colinhacks/zod

github.com

 

 

* 스키마 선언이란?

import { z } from 'zod';

// 사용자 데이터 구조 정의
const UserSchema = z.object({
  name: z.string(), // 이름은 문자열이어야 함
  age: z.number(), // 나이는 숫자여야 함
  email: z.string().email() // 이메일 형식이어야 함
});
  • 데이터의 구조와 규칙을 미리 정의하는 것
  • (데이터가 어떤 형태여야 하는지, 어떤 제약조건을 가져야 하는지를 명시)

 

 

주요 장점

1. 런타임 타입 안정성

  • TypeScript는 컴파일 타임에만 타입 체크를 수행하지만, Zod는 런타임에서도 데이터 유효성을 검증한다.
  • 외부 데이터(API 응답, 사용자 입력)의 안전성을 보장할 수 있다.

2. 스키마 재사용성과 타입추론

  • 한 번 정의한 스키마를 여러 곳에서 재사용할 수 있다.
  • 스키마에서 TypeScript 타입을 자동으로 추론

3. 풍부한 유효성 검사와 에러 처리

  • 다양한 유효성 검사 기능 제공
  • 명확한 에러 메시지와 처리 방법

4. 개발 편의성

  • 의존성 없는 독립적인 라이브러리
  • 직관적이고 간단한 API 구조

 

주요 단점

1. 번들 크기 증가

  • 프로덕션 번들에 포함되어 앱 크기가 커질 수 있음

2. 런타임 오버헤드

  • 대규모 데이터나 복잡한 스키마의 경우 약간의 성능 저하가 발생할 수 있음

3. 학습 곡선

  • 복잡한 스키마를 작성할 때 초기 학습이 필요

4. 유연성 부족

  • 개발자가 원하는 수준의 유연성을 제공하지 못할 수 있음

 

주요 사용 방법

1. 기본 타입 정의

const stringSchema = z.string();
const numberSchema = z.number();
const booleanSchema = z.boolean();
const nullSchema = z.null();
const undefinedSchema = z.undefined();

 

2. 객체 스키마

const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
  age: z.number().optional(),
  metadata: z.record(z.string()) // 동적 키를 가진 객체
});

 

3. 배열 스키마

const numberArray = z.array(z.number());
const stringArray = z.string().array();
const tupleSchema = z.tuple([z.string(), z.number()]);

 

 

스키마 메서드

[유효성 검사 메서드]

1. parse

const stringSchema = z.string();

stringSchema.parse("fish"); // => returns "fish"
stringSchema.parse(12); // throws error
  • 정의된 스키마에 대해 데이터의 유효성을 검증한다.
  • 데이터가 유효하면 전달한 값의 깊은 복사본이 반환됨
  • 데이터가 유효하지 않으면(실패 시) 에러를 발생시킴 (throw error)
  • try-catch 블록으로 에러 처리를 해줘야 한다.

2. safeParse

stringSchema.safeParse(12);
// => { success: false; error: ZodError }

stringSchema.safeParse("billie");
// => { success: true; data: 'billie' }
  • 성공/실패 여부와 데이터/에러를 객체로 반환
  • 검증에 실패했을 때 에러를 throw 하지 않고 결과 객체를 반환
  • 에러 처리가 필요하지만 try-catch를 사용하고 싶지 않을 때 유용하다.

3. parseAsync

const stringSchema = z.string().refine(async (val) => val.length <= 8);

await stringSchema.parseAsync("hello"); // => returns "hello"
await stringSchema.parseAsync("hello world"); // => throws error
  • 비동기 검증이 필요한 경우 사용
  • Promise 를 반환하고 검증 실패 시 에러를 throw
  • 비동기 검증이 필요하지만 에러 throw를 피하고 싶다면 safeParseAsync를 대신 사용할 수 있음

4. refine

const myString = z.string().refine((val) => val.length <= 255, {
  message: "String can't be more than 255 characters",
});
  • 기본 유효성 검사 외 사용자 정의(커스텀) 검증 로직을 추가할 수 있게 해주는 기능
  • 비동기 검증 시 parseAsync 와 같이 사용해야 오류가 발생하지 않음

 

[변환 메서드]

- transform

const emailToDomain = z
  .string()
  .email()
  .transform((val) => val.split("@")[1]);

emailToDomain.parse("colinhacks@example.com"); // => example.com
  • 스키마의 유효성 검사가 완료된 후 데이터를 원하는 형태로 변환할 수 있게 해주는 기능

 

[조합 메서드]

// 유니온 타입
const stringOrNumber = z.union([z.string(), z.number()]);

// 인터섹션 타입
const combinedSchema = z.intersection(
  z.object({ name: z.string() }),
  z.object({ age: z.number() })
);

 

 

[선택적 필드]

const optionalString = z.string().optional(); // string | undefined
const nullableString = z.string().nullable(); // string | null
const nullishString = z.string().nullish(); // string | null | undefined

 

1. optional

  • 필수 입력을 선택적 입력으로 변경하는 메서드(undefined를 허용하도록 만듦)

2. nullable

  • null 값을 허용하도록 만드는 메서드(undefined는 허용X)

3. nullish

  • optional과 nullable을 동시에 적용한 것과 같은 효과를 주는 메서드
  • null과 undefined 둘 다 허용

 

[문자열 유효성 검사 옵션]

z. string (). min ( 5 , { message : "5자 이상이어야 합니다." }); 
z. string (). max ( 5 , { message : "5자 이하여야 합니다." }); 
z. string (). length ( 5 , { message : "정확히 5자여야 합니다." }); 
z. string (). email ({ message : "잘못된 이메일 주소입니다." }); 
z. string (). url ({ message : "잘못된 url입니다." }); 
z. string (). emoji ({ message : "이모지가 아닌 문자가 포함되어 있습니다." }); 
z. string (). uuid ({ message : "잘못된 UUID입니다." }); 
z. string (). includes ( "tuna" , { message : "tuna를 포함해야 합니다." }); 
z. string (). startsWith ( "https://" , { message : "보안 URL을 제공해야 합니다." }); 
z. string (). endsWith ( ".com" , { message : ".com 도메인만 허용됩니다" }); 
z. string (). datetime ({ message : "날짜/시간 문자열이 잘못되었습니다! UTC여야 합니다." }); 
z. string (). ip ({ message : "IP 주소가 잘못되었습니다" });

 

 

 

- 더 다양한 메서드는 zod 공식 문서에 잘 정리되어 있다!

 

 

React Hook Form과 Zod

  • react-hook-form 과 zod 를 통합해 복잡한 폼 관리와 유효성 검사를 간편하게 처리할 수 있다.
  • zodResolver를 통해 두 라이브러리를 쉽게 통합이 가능하다.
  • Zod : 런타임 시점의 타입 검증 제공
  • React Hook Form : 불필요한 리렌더링 방지

 

 

🧐 느낀점

개인프로젝트의 회원가입 기능 구현 중 이전에 들어보았던 react-hook-form 과 zod 를 활용해서 구현하고자 먼저 zod 에 대해서 정리해보면서 구조와 사용방법에 대해서 공부했다. react-hook-form 도 좀 더 정리해보고 프로젝트에 적용해 볼 예정이다!

'Library' 카테고리의 다른 글

React Hook Form  (0) 2025.01.22