타입스크립트 친화적인 스키마 기반 유효성 검사 라이브러리
zod 스키마 정의
import { z } from 'zod';
export const loginSchema = z.object({
email: z.string().email({ message: '유효한 이메일을 입력해주세요.' }),
password: z.string().min(6, { message: '비밀번호는 최소 6자 이상이어야 합니다.' })
});
z.object({...}) 스키마 정의 시작
z.string().email() 문자열 & 이메일 형식 검사
min(n) / max(n) 길이 제한
폼 설정
import { useForm } from 'react-hook-form';
import { zooResolver } from '@hookform/resolvers/zod';
import { loginSchema } from '@/schema/loginSchema';
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(loginSchema),
});
zodResolver RHF와 스키마 연결
JSX에서 사용
<form onSubmit={ handleSubmit(data => console.log(data))}>
<input {...register('email')} placeholder="이메일" />
{errors.email && <p>{errors.email.message}</p>}
</form>
체크박스 배열
const schema = z.object({
items: z.array(z.string()).min(1, '하나 이상 선택해주세요.'),
})
{options.map(item => (
<label key={item}>
<input
type='checkbox'
value={item}
{...register('items')}
/>
{item}
</label>
))}
zod props
| 타입 | 메서드 | 설명 |
| z.string() | .min(n), .max(n), .email(), .regex() | 문자열 검사 |
| z.number() | .min(n), .max(n), .int(), .positive() | 숫자 검사 |
| z.boolean() | - | 불리언 검사 |
| z.array() | .length(n), .min(n), .max(n) | 배열 검사 |
| z.enum() | z.enum(['a', 'b']) | enum 값 제한 |
| z.union() | z.union([z.string(), z.number()]) | 여러 타입 중 하나 허용 |
| z.object() | 필드 정의 | 객체 검사 |
| z.optional() | 필수 아님 | 옵션 필드 지정 |
| z.nullable() | null 허용 | null 허용 필드 |
| z.literal() | 특정 값만 허용 | z.literal('admin') |
유효성 메시지 커스터마이징
const schema = z.object({
email: z.string()
.email({ message: '올바른 이메일 형식이 아닙니다.' }),
password: z.string()
.min(6, { message: '비밀번호는 최소 6자리 이상입니다.' }),
});
객체 구조 유효성 검사
const schema = z.object({
user: z.object({
name: z.string(),
phone: z.string().regex(/^010\d{8}$/),
}),
});
배열 유효성 검사
const schema = z.object({
items: z.array(z.string()).min(1, { message: '하나 이상 선택해주세요.' }),
});
조건부 검사(.refine)
const schema = z.object({
password: z.string().min(6),
confrimPassword: z.string(),
}).refine(data => data.password === data.confirmPassword, {
path: ['confirmPassword'],
message: '비밀번호가 일치하지 않습니다.',
});
optional / nullable
.optional() : 값이 없어도 통과됨 (undefined 허용)
.nullable() : null 허용됨
.nullish() : null 또는 undefined 허용
z.string().optional(); // string | undefined
z.string().nullable(); // string | null
z.string().nullish(); // string | null | undefined
react-hook-form과 연동
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
const { register, handleSubmit, formState: { errors }} = useForm({
resolver: zodResolver(schema),
});
기본값 설정 (.default())
z.string().default('기본값')
커스텀 유효성 검사 (refine())
z.string().refine(val => val.startsWith('A'), {
message: 'A로 시작해야 합니다.',
});
사용자 정의 에러 던지기 (safeParse())
const result = schema.safeParse(data);
if (!result.success) {
console.log(result.error.format());
}
'카테캠 > 2단계' 카테고리의 다른 글
| [7/16] Promise (0) | 2025.07.16 |
|---|---|
| [7/15] 동기식 vs 비동기식 (3) | 2025.07.16 |
| [7/10] useFormContext (1) | 2025.07.14 |
| [7/10] 고차 함수 (0) | 2025.07.10 |
| [7/9] 중복 전화번호 검사, 모달 취소 시 되돌리기 (1) | 2025.07.09 |