본문 바로가기

[TypeScript] 속성 검증 라이브러리 비교 분석

민이(MInE) 2025. 1. 7.
반응형

목차

  1. 라이브러리 개요
  2. 기능 비교
  3. 성능 분석
  4. 사용 사례

라이브러리 개요

1. Zod

import { z } from "zod";

const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  age: z.number().min(0).max(120)
});

2. Joi

import * as Joi from 'joi';

const schema = Joi.object({
  username: Joi.string().min(3).max(30).required(),
  email: Joi.string().email().required()
});

3. Yup

import * as yup from 'yup';

const schema = yup.object({
  name: yup.string().required(),
  age: yup.number().positive().integer()
});

4. Lodash

import * as _ from 'lodash';

const validateUser = (user: unknown) => {
  if (!_.isObject(user)) return false;
  return _.every([
    _.has(user, 'name') && _.isString(user.name),
    _.has(user, 'age') && _.isNumber(user.age)
  ]);
};

기능 비교

1. 타입 안전성

  • Zod: ⭐⭐⭐⭐⭐

    • 최고 수준의 TypeScript 통합
    • 자동 타입 추론
  • Joi: ⭐⭐⭐

    • TypeScript 지원은 있으나 제한적
  • Yup: ⭐⭐⭐⭐

    • TypeScript 지원 우수
  • Lodash: ⭐⭐

    • 타입 검사는 가능하나 TypeScript 통합 제한적

2. 검증 기능

// Zod
const ResourceSchema = z.object({
  type: z.enum(["vpc", "subnet"]),
  config: z.record(z.unknown())
});

// Joi
const schema = Joi.object({
  type: Joi.string().valid('vpc', 'subnet'),
  config: Joi.object().pattern(Joi.string(), Joi.any())
});

// Yup
const schema = yup.object({
  type: yup.string().oneOf(['vpc', 'subnet']),
  config: yup.object().test(value => true)
});

// Lodash
const validateResource = (resource: unknown) => {
  return _.isObject(resource) &&
    _.has(resource, 'type') &&
    _.includes(['vpc', 'subnet'], resource.type) &&
    _.isObject(_.get(resource, 'config'));
};

3. 커스텀 검증

// Zod
const withCustomValidation = z.object({}).refine(
  data => customValidation(data),
  "Custom validation failed"
);

// Joi
const withCustomValidation = Joi.object().custom((value, helpers) => {
  if (!customValidation(value)) {
    return helpers.error('custom.invalid');
  }
  return value;
});

// Yup
const withCustomValidation = yup.object().test(
  'custom',
  'Custom validation failed',
  value => customValidation(value)
);

// Lodash
const withCustomValidation = (data: unknown) => {
  return _.conformsTo(data, {
    field: value => customValidation(value)
  });
};

성능 분석

번들 크기

const bundleSizes = {
  zod: '17.5kB',
  joi: '97.1kB',
  yup: '37.2kB',
  lodash: '71.5kB'  // 전체 패키지 기준
};

검증 속도 (10,000회 실행)

const benchmarkResults = {
  zod: 145,      // ms
  joi: 320,      // ms
  yup: 210,      // ms
  lodash: 95     // ms (단순 타입 체크 기준)
};

사용 사례

1. 복잡한 객체 구조 검증

// Zod
const ComplexSchema = z.object({
  nested: z.object({
    array: z.array(z.string())
  }).optional()
});

// Lodash
const validateComplex = (data: unknown) => {
  return _.isObject(data) &&
    (_.isUndefined(data.nested) || 
     (_.isObject(data.nested) && 
      _.isArray(data.nested.array) &&
      _.every(data.nested.array, _.isString)));
};

2. 조건부 검증

// Zod
const ConditionalSchema = z.object({
  type: z.string(),
  data: z.any().refine(
    (data, ctx) => ctx.parent.type === 'number' ? _.isNumber(data) : true
  )
});

// Lodash
const validateConditional = (obj: unknown) => {
  if (!_.isObject(obj)) return false;
  if (obj.type === 'number') {
    return _.isNumber(obj.data);
  }
  return true;
};

각 라이브러리의 특징적 장점

Zod

  • 강력한 TypeScript 통합
  • 런타임 타입 안전성
  • 직관적인 API

Joi

  • 풍부한 검증 규칙
  • 상세한 에러 메시지
  • 깊은 객체 검증

Yup

  • Form 라이브러리 통합
  • Promise 기반 검증
  • 직관적인 API

Lodash

  • 가볍고 빠른 검증
  • 유연한 커스텀 검증
  • 다양한 유틸리티 함수 제공

권장 사용 상황

Zod 권장

  • TypeScript 프로젝트
  • 복잡한 타입 검증
  • 강력한 타입 추론 필요

Lodash 권장

  • 간단한 타입 체크
  • 유연한 커스터마이징
  • 성능이 중요한 경우

Joi 권장

  • 복잡한 검증 규칙
  • 상세한 에러 처리
  • JavaScript 프로젝트

Yup 권장

  • Form 검증
  • 간단한 객체 검증
  • Promise 기반 로직

결론

각 라이브러리는 고유한 장점이 있습니다:

  • Zod: 타입 안전성과 검증을 모두 잡고 싶을 때
  • Lodash: 간단하고 유연한 검증이 필요할 때
  • Joi: 복잡한 검증 규칙이 필요할 때
  • Yup: 폼 검증이 주요 사용 사례일 때
    이러한 비교를 통해, TypeScript 프로젝트에서의 리소스 속성 검증에는 Zod가 가장 적합한 선택임을 알 수 있습니다. Zod는 뛰어난 TypeScript 지원, 높은 성능, 그리고 타입 안전성을 제공하면서도 직관적인 API를 제공합니다.
반응형

댓글