728x90
728x90

Zod 라이브러리

들어가며

  • 타입스크립트(TypeScript)에서 유효성 검사를 쉽게 해주는 Zod 라이브러리에 대해 정리해본다.

 

Zod 라이브러리

개념

  • 타입스크립트(TypeScript)에서 유효성 검사를 쉽게 해주는 스키마 선언 및 데이터 검증 라이브러리
  • 타입 안전성을 유지하면서 데이터의 유효성을 검사할 수 있도록 설계되어 있다.
    • 데이터 검증을 더욱 명확하고 직관적으로 수행할 수 있도록 도와준다.

 

설치

$ npm install zod   # yarn add zod

 

주요 기능

  • 다양한 데이터 타입에 대해 스키마를 선언할 수 있다.
import { z } from "zod";

const userSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
});

 

  • 선언한 스키마를 통해 입력 데이터를 검증할 수 있다.
const userData = {
  name: "John",
  age: 30,
  email: "john@example.com",
};

const parsedData = userSchema.safeParse(userData);

if (parsedData.success) {
  console.log("검증 통과:", parsedData.data);
} else {
  console.log("검증 실패:", parsedData.error);
}

 

  • @safeParse@ 메서드성공 여부에 따라 @success@ 플래그와 데이터를 포함한 결과를 반환한다.

 

  • @parse@ 메서드유효성 검사 실패 시 예외를 발생시키기 때문에, 더 강력한 에러 처리가 필요할 때 사용한다.
  • 스키마에서 선언한 타입을 기반으로 타입스크립트의 타입을 자동으로 유추할 수 있다.
type User = z.infer<typeof userSchema>;

 

  • 검증 실패 시 사용자 정의 에러 메시지를 설정할 수 있다.
const ageSchema = z.number().min(18, "나이는 18세 이상이어야 합니다.");

 

  • 조건에 따라 스키마를 동적으로 만들 수 있다.
const dynamicSchema = z.object({
  role: z.enum(["admin", "user"]),
  permissions: z.array(z.string()).optional(),
});

 

사용하는 이유

  • 타입스크립트는 컴파일 타임의 타입을 보장하지만, 런타임의 타입을 보장해주지는 못한다.
  • 하지만, Zod를 이용할 경우, 컴파일 타임 뿐만 아니라 런타임의 타입을 보장해준다.
    • 따라서 개발 과정에서의 오류를 사전에 방지할 수 있다.

 

예제 코드 : Zod 라이브러리를 사용하지 않을 경우
  • 타입스크립트만 이용할 경우, 컴파일 타임의 타입이 보장되지만, 런타임의 타입이 보장되지 않는다.
  • 따라서 아래의 코드와 같이 미리 정의한 속성과 타입이 페치해오는 데이터에 없어도 타입 검사가 되지 않는다.
    • 이 문제는 런타임 때 발생한다.
const url = 'https://api.example.com/data';

// 페치할 데이터 타입 정의
type Tour = {
  id: string;
  name: string;
  info: string;
  image: string;
  price: string;
  something: number,    // 페치해온 데이터에 없는 속성과 타입 추가
};

async function fetchData(url: string): Promise<Tour[]> {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data: Tour[] = await response.json();
    console.log(data);
    
    return data;
  } catch (error) {
    const errMsg =
      error instanceof Error ? error.message : 'There was an error...';
    console.error(errMsg);

    return [];
  }
}

const tours = await fetchData(url);

tours.map((tour) => {
  console.log(tour.name);
});

Zod를 사용하지 않을 경우, 타입 검사가 되지 않는다. (페치해온 데이터에는 number 타입의 something 속성이 존재하지 않는다.)

 

예제 코드 : Zod 라이브러리를 사용할 경우
  • Zod 라이브러리를 사용할 경우, 미리 정의한 속성과 타입페치해오는 데이터에 없으면 타입 체크를 해준다.
import { z } from 'zod';

const url = 'https://api.example.com/data';

// zod를 이용하면 런타입 때 타입을 체크할 수 있다.
// - zod를 이용하지 않을 경우 빌드타임 때만 타입을 체크할 수 있다.
const tourSchema = z.object({
  id: z.string(),
  name: z.string(),
  info: z.string(),
  image: z.string(),
  price: z.string(),
  something: z.number(),   // 페치해온 데이터에 없는 속성과 타입 추가
});

type Tour = z.infer<typeof tourSchema>;

async function fetchData(url: string): Promise<Tour[]> {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const rawData: Tour[] = await response.json();

    const result = tourSchema.array().safeParse(rawData);
    console.log(result);

    if (!result.success) {
      throw new Error(`Invalid data: ${result.error}`);
    }

    return result.data;
  } catch (error) {
    const errMsg =
      error instanceof Error ? error.message : 'There was an error...';
    console.error(errMsg);
    return [];
  }
}

const tours = await fetchData(url);

tours.map((tour: any) => {
  console.log(tour.name);
});

데이터 페치 후 타입 검사가 진행된 모습

 

장점

  • 타입스크립트와 완벽하게 통합되어 타입 검사를 강화한다.
  • 복잡한 데이터 구조를 처리할 수 있도록 배열, 객체, 튜플 등의 스키마를 지원한다.
  • 기본 제공하는 스키마 외에도 사용자 정의 검증 로직을 추가할 수 있다.
const passwordSchema = z.string().refine((val) => val.length >= 6, {
  message: "비밀번호는 최소 6자 이상이어야 합니다.",
});

 

참고 사이트

 

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

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

github.com

728x90
728x90