Front-End프로그래밍

[Vue3, TypeScript] vee-validate와 yup에 대한 예제 총정리

vee-validateyup은 둘 다 웹 폼의 유효성 검사(validation) 를 도와주는 라이브러리지만, 역할사용 방식이 다릅니다.
둘의 차이점과 각각의 목적을 아래에 정리해드릴게요.


ee-validate란?

Vue.js 전용 폼 유효성 검사 라이브러리

vee-validateVue.js (특히 Composition API) 프로젝트에서 폼 상태 관리 + 유효성 검사를 간편하게 할 수 있게 해주는 라이브러리입니다.

주요 기능

기능설명
useForm()폼 전체의 상태와 동작을 관리
Field 컴포넌트입력 필드 바인딩 + 유효성 검사 연결(개별 폼 필드 관리)
Form 컴포넌트폼 제출 처리
ErrorMessage 컴포넌트필드의 에러 메시지 출력
yup, zod 등의 스키마와 연동 가능스키마 기반 유효성 검사 사용 가능

사용 기술

  • Vue 3 Composition API에 최적화
  • 선언적이고 타입 안전한 유효성 검사


useForm in vee-validate

import { useForm, Field } from 'vee-validate';

실제 사용 예시(템플릿)

<template>
  <form @submit="onSubmit">
    <Field name="customerNm" as="input" />
    <Field name="contractNo" as="input" />
    <button type="submit">제출</button>
    <button type="button" @click="resetForm">초기화</button>
  </form>
</template>

<script lang="ts" setup>
import { useForm, Field } from 'vee-validate';

const { handleSubmit, resetForm } = useForm({
  initialValues: {
    contractNo: '',
    customerNm: '',
  },
});

const onSubmit = handleSubmit((values) => {
  console.log('제출된 값:', values);
});
</script>

타입스크립트 연동 팁

interface FormValues {
  contractNo: string;
  customerNm: string;
  // ...생략
}

const { handleSubmit } = useForm<FormValues>({
  initialValues: {
    contractNo: '',
    customerNm: '',
    // ...
  }
});


yup이란?

자바스크립트/타입스크립트용 유효성 검사 라이브러리

yup은 독립적인 스키마 기반 유효성 검사 도구입니다.
객체의 구조를 정의하고, 그 구조에 맞는 유효성 조건을 선언적으로 작성할 수 있습니다.

주요 기능

기능설명
객체 스키마 정의.object({ ... })로 객체 구조 선언
필드 유효성 검사.required(), .min(), .matches()
커스텀 메시지각 조건에 맞는 에러 메시지 지정 가능
비동기 유효성 검사.test()를 통해 async 유효성 검사도 가능
타입 추론yup.InferType<typeof schema> 로 타입 추론 가능 (하지만 제한적)

관계: 왜 둘을 같이 쓰는가?

vee-validate는 폼 입력과 상태를 관리하고,
yup은 유효성 검사만을 담당합니다.

이 둘은 아래처럼 연결됩니다:

const schema = yup.object({
  name: yup.string().required('이름은 필수입니다.'),
});

useForm({
  validationSchema: schema
});

vee-validateyup 스키마를 기반으로 유효성 검사를 자동으로 처리해줍니다.


둘의 차이 요약

항목vee-validateyup
목적Vue 컴포넌트에서 폼 상태 및 유효성 관리유효성 로직만 담당
종속성Vue.js 필요Vue, React 등과 무관 (독립적)
사용 방식<Form>, <Field>, useForm() 등 제공schema.validate() 형태로 사용
주 사용처Vue 프로젝트 전용다양한 JS 프로젝트
조합yup, zod, joi 등과 연동단독 사용 가능

실제 예시 (함께 쓰는 모습)

// yup 스키마 정의
const schema = yup.object({
  email: yup.string().email().required(),
  password: yup.string().min(6).required()
});

// vee-validate로 연결
const { handleSubmit } = useForm({
  validationSchema: schema
});

const onSubmit = handleSubmit(values => {
  console.log('제출 성공:', values);
});

useFormvalidationSchema 추가

import { useForm, Field, Form } from 'vee-validate';
import * as yup from 'yup';

const schema = yup.object({
  customerNm: yup.string().required('고객명은 필수입니다.'),
  contractNo: yup.string().length(10, '계약번호는 10자여야 합니다.'),
  customerHp: yup
    .string()
    .matches(/^\d{3}-\d{3,4}-\d{4}$/, '올바른 전화번호 형식이 아닙니다.'),
});

const { handleSubmit, resetForm } = useForm({
  validationSchema: schema,
});


템플릿 예시 (Vue 3 <script setup>)

<template>
  <Form @submit="onSubmit">
    <div>
      <label>고객명</label>
      <Field name="customerNm" as="input" />
      <ErrorMessage name="customerNm" />
    </div>

    <div>
      <label>계약번호</label>
      <Field name="contractNo" as="input" />
      <ErrorMessage name="contractNo" />
    </div>

    <div>
      <label>전화번호</label>
      <Field name="customerHp" as="input" />
      <ErrorMessage name="customerHp" />
    </div>

    <button type="submit">제출</button>
  </Form>
</template>

<script lang="ts" setup>
import { useForm, Field, Form, ErrorMessage } from 'vee-validate';
import * as yup from 'yup';

const schema = yup.object({
  customerNm: yup.string().required('고객명은 필수입니다.'),
  contractNo: yup.string().length(10, '계약번호는 10자여야 합니다.'),
  customerHp: yup
    .string()
    .matches(/^\d{3}-\d{3,4}-\d{4}$/, '올바른 전화번호 형식이 아닙니다.'),
});

const { handleSubmit, resetForm } = useForm({
  validationSchema: schema,
});

const onSubmit = handleSubmit((values) => {
  console.log('제출 성공:', values);
});
</script>


어떤 걸 선택하면 좋을까?

상황추천
간단하고 직관적인 유효성 검사yup
TypeScript 기반 타입 추론 최우선zod + @vee-validate/zod
복잡한 조건 분기나 커스텀 타입 검사 zod

vee-validate에서 커스텀 유효성 검사 작성법

vee-validate에서 커스텀 유효성 검사(Custom Validation) 를 작성하는 방법은 크게 두 가지가 있습니다


1. useField / Field에서 직접 커스텀 검사 함수 정의

가장 직관적이고 간단한 방법입니다.

📌 예시: 이름이 반드시 “홍길동”이어야 하는 필드

<template>
  <Form @submit="onSubmit">
    <div>
      <label>이름</label>
      <Field
        name="name"
        as="input"
        :rules="isHongGildong"
      />
      <ErrorMessage name="name" />
    </div>

    <button type="submit">제출</button>
  </Form>
</template>

<script lang="ts" setup>
import { Field, Form, ErrorMessage, useForm } from 'vee-validate';

const isHongGildong = (value: string) => {
  if (value !== '홍길동') {
    return '이름은 반드시 홍길동이어야 합니다.';
  }
  return true;
};

const { handleSubmit } = useForm();

const onSubmit = handleSubmit(values => {
  console.log('성공적으로 제출됨:', values);
});
</script>

2. 글로벌 커스텀 유효성 규칙 등록 (defineRule 사용)

이 방법은 재사용 가능한 커스텀 규칙을 만드는 데 적합합니다.

📌 예시: 전화번호가 010- 으로 시작해야 하는 규칙

// main.ts 또는 setup 파일에 작성
import { defineRule } from 'vee-validate';

defineRule('startsWith010', (value: string) => {
  if (!value.startsWith('010-')) {
    return '전화번호는 010-으로 시작해야 합니다.';
  }
  return true;
});

📌 템플릿에서 사용

<Field name="phone" as="input" rules="required|startsWith010" />
<ErrorMessage name="phone" />

✅ 여러 개의 기본 rule (required, email 등)과 조합 가능


3. yup 또는 zod를 사용하는 경우의 커스텀 검사

📌 yup 예시 – 조건부 검사

import * as yup from 'yup';

const schema = yup.object({
  email: yup
    .string()
    .email('이메일 형식이 아닙니다.')
    .test('is-gmail', 'gmail만 허용됩니다.', (value) => {
      return value?.includes('@gmail.com');
    }),
});


정리 – 선택 기준

방식사용 상황장점예시
Field에서 함수 전달단순한 1회성 검사간단하고 빠름:rules="value => value === '홍길동'"
defineRule여러 곳에서 반복 사용재사용 가능전화번호, 사용자 정의 포맷
yup.test() / zod.refine()스키마 기반 검사 사용 시스키마 일관성 유지조건부 검사, 커스텀 메시지

✨ 참고: async 커스텀 유효성 검사 (예: 서버 중복 체크)

defineRule('uniqueUsername', async (value: string) => {
  const res = await fetch(`/api/check-username?name=${value}`);
  const { isTaken } = await res.json();
  return isTaken ? '이미 사용 중인 아이디입니다.' : true;
});

비동기 커스텀 검사는 버튼 디스에이블 처리 등과 함께 고려하면 UX가 좋아집니다.


4. 커스텀 rule에 파라미터 전달하기

🔧 defineRule에서 매개변수 받기

vee-validatedefineRule 함수에서 두 번째 인자로 params를 넘겨줍니다.

📌 예시: minLength 커스텀 룰

import { defineRule } from 'vee-validate';

defineRule('minLength', (value: string, [limit]: [number]) => {
  if (!value || value.length < limit) {
    return `최소 ${limit}자 이상 입력해야 합니다.`;
  }
  return true;
});

📌 템플릿에서 사용

<Field name="username" rules="required|minLength:5" />
<ErrorMessage name="username" />

⚠️ 파라미터는 문자열로 전달되므로 내부에서 Number()로 변환하는 게 안전할 수 있어요.


5. 커스텀 컴포넌트 안에서 useField()로 유효성 검사 적용

✨목표: MyInput.vue 같은 사용자 정의 <input>vee-validate에 연결


📦 MyInput.vue

<template>
  <div>
    <label>{{ label }}</label>
    <input v-bind="field" v-model="value" :type="type" />
    <span v-if="errorMessage" style="color: red;">{{ errorMessage }}</span>
  </div>
</template>

<script lang="ts" setup>
import { useField } from 'vee-validate';
import { computed, defineProps } from 'vue';

const props = defineProps<{
  name: string;
  label: string;
  rules?: any;
  type?: string;
}>();

const { value, errorMessage, field } = useField(props.name, props.rules);
</script>

📦 상위 컴포넌트 사용 예시

<template>
  <Form @submit="onSubmit">
    <MyInput name="email" label="이메일" rules="required|email" />
    <MyInput name="nickname" label="닉네임" rules="required|minLength:3" />
    <button type="submit">제출</button>
  </Form>
</template>

<script setup lang="ts">
import { Form, useForm } from 'vee-validate';
import MyInput from './MyInput.vue';

const { handleSubmit } = useForm();

const onSubmit = handleSubmit((values) => {
  console.log('성공:', values);
});
</script>

정리 요약

기능설명예시
defineRule + 파라미터커스텀 rule에 :5 같은 값 전달minLength:5
useField()커스텀 input 컴포넌트에서 vee-validate와 연결value, errorMessage, field 반환
커스텀 컴포넌트 사용폼 내에서 Field 대신 커스텀 UI 사용 가능<MyInput name="..." />

✨ 보너스: 커스텀 컴포넌트에서 emit('update:modelValue')로 통신하려면?

<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

<script setup lang="ts">
defineProps<{ modelValue: string }>();
defineEmits(['update:modelValue']);
</script>

vee-validate<Field as="MyInput" />로도 연결할 수 있습니다.

요약 한 줄 정리

  • vee-validate: Vue 3에서 폼 상태 및 유효성 관리를 담당하는 Vue 전용 라이브러리
  • yup: JavaScript/TypeScript에서 스키마 기반 유효성 검사를 담당하는 범용 라이브러리
  • 함께 사용하면: Vue 프로젝트에서 타입 안전한, 깔끔한 폼 유효성 검사가 가능해짐

[연관자료]

[Vue3, TypeScript] vee-validate + pinia 연동 방법 예제 총정리

[Vue3, TypeScript] vee-validate에서 입력 필드 마스킹/포맷팅방법

JavaScript/TypeScript 기본 문법: Spread, Rest, Map 사용법 예제 총정리

[Vue3, TypeScript] vee-validate와 yup에 대한 예제 총정리

error: Content is protected !!