Zod로 유효성 검증과 타입 선언의 두 마리 토끼 잡기
이전 포스팅에서 타입스크립트로 코드를 작성하는 것과 무관하게 왜 자바스크립트 프로그램에서 유효성 검증이 필요한지에 대해서 알아보았는데요.
이번 포스팅에서는 최근 개발자들로부터 많은 인기를 끌고 있는 Zod를 사용하는 전반적인 방법에 대해서 알아보겠습니다.
라이브러리 설치
프로젝트에 zod라는 패키지를 npm으로 설치합니다.
$ npm i zod
그리고 Zod를 사용하실 때는 가급적 타입스크립트는 strict 모드로 쓰시기를 추천드릴게요.
{
"compilerOptions": {
"strict": true
}
}
이제 zod 패키지에서 z를 불러올 수 있으며, 이 녀석만 있으면 우리는 Zod의 모든 기능을 활용할 수 있습니다.
import { z } from "zod";
스키마 정의
Zod를 사용할 때 제일 먼저 해야되는 것은 스키마(schema)를 정의하는 것입니다.
여기서 스키마란 쉽게 말해서 데이터의 형태와 구조를 뜻하는데요. 예를 들어, 이메일, 나이, 활성화 여부로 이루어진 사용자 객체를 나타내는 스키마를 Zod로 정의해보겠습니다.
const User = z.object({
email: z.string(),
age: z.number(),
active: z.boolean(),
});
z.object()를 사용하여 User 스키마가 객체의 형태이고, z.string()으로 email 속성은 문자열, age 속성은 z.number()로 숫자, active 속성은 z.boolean()으로 불리언 형태입니다.
뭐, 별 거 없죠? 그런데 API가 굉장히 간단하고 명료하지 않나요?
Zod를 처음 사용하시는 분들도 이러한 직관적인 API 덕분에 큰 어려움 없이 배울 수 있답니다.
유효성 검증
Zod 스키마를 정의하고 나면 유효성 검증을 해볼 수 있는데요.
스키마의 parse() 함수에 검증하고 싶은 값을 넘겨서 호출하면 됩니다.
User.parse({
email: "user@test.com",
age: 35,
active: true,
}); // ✅ 유효성 검증 통과
User.parse({
email: "user@test.com",
age: "35",
}); // ❌ 유효성 검증 실패
검증이 실패할 경우에는 parse() 함수는 오류(error)를 발생시키는데요.
정확히 어느 부분에서 어떤 검증을 통과하지 못했는지가 나와서 매우 유용합니다.
ZodError: [
{
code: "invalid_type",
expected: "number",
received: "string",
path: ["age"],
message: "Expected number, received string",
},
{
code: "invalid_type",
expected: "boolean",
received: "undefined",
path: ["active"],
message: "Required",
},
];
여기서 한 가지 주의할 부분은 검증이 성공했을 경우 parse() 함수가 반환하는 객체에는 검증에 통과한 속성만 포함된다는 것입니다.
예를 들어, 다음과 같이 스키마에 정의되지 않은 password 속성을 입력 객체에 포함한 경우,
const user = User.parse({
email: "user@test.com",
age: 35,
active: true,
password: "abcd1234",
});
console.log(user);
parse() 함수가 반환한 결과 객체에는 해당 속성이 제외되어 있는 것을 볼 수 있습니다.
{
email: "user@test.com",
age: 35,
active: true,
}
이것은 parse() 함수의 반환 타입이 정의된 스키마에 의해서 결정이 되기 때문입니다.
타입에 password 속성이 없는데 값에만 password 속성이 들어있다면 타입 에러가 발생했을 것입니다.
console.log(user);
// ^? const user: { email: string; age: number; active: boolean; }
이처럼 Zod는 타입스크립트에 아주 친화적으로 설계되어 있어서 견고한 코드를 작성하는데도 도움을 줍니다.
타입 추론
뿐만 아니라 Zod는 스키마를 기준으로 타입스크립트 타입을 알아서 추론할 수도 있는데요. 이 기능을 잘 활용하면 아예 타입을 따로 작성할 필요가 없어지고 따라서 타입을 스키마와 서로 맞춰 줄 걱정이 사라집니다.
예를 들어서, 사용자 객체를 입력으로 받는 함수를 타입스크립트로 작성하려면 아래와 같이 입력 타입을 작성해줘야하는데요.
// 내가 직접 타입을 작성
interface User {
email: string;
age: number;
active: boolean;
}
function processUser(user: User) {
User.parse(user); // 유효성 검증
// 사용자 처리 로직
}
하지만 Zod의 infer과 자바스크립트의 typeof 연산자를 사용하면 이미 정의한 스키마로 부터 타입을 뽑아낼 수 있습니다.
// 스카마로부터 타입을 추론 👍
type User = z.infer<typeof User>;
function processUser(user: User) {
User.parse(user); // 유효성 검증
// 사용자 처리 로직
}
스키마 하나 작성해서 유효성 검증도 하고 타입스크립트 타입도 뽑아내고 완전 꿩먹고 알먹고 아닌가요? 😁
예제의 스키마는 단순해서 타입을 직접 작성하시는 게 대수롭지 않게 느껴질 수도 있는데요. 실제 프로젝트에서는 훨씬 복잡한 스키마를 다루실 때는 Zod의 이러한 편리함이 훨씬 크게 느껴질 것입니다.
직접 작성한 타입과 스키마가 항상 서로 일치하도록 관리한다는 게 여간 번거로운 일이 아니며 까먹기도 참 쉽거든요. Zod를 사용하면 스키마 활용을 극대화하고 불필요한 타입을 작성을 최소화할 수 있어서 개발 생산성이나 유지 보수 측면에서 큰 도움을 받을 수 있습니다.
마치며
지금까지 Zod를 사용하여 어떻게 유효성 검증과 타입 선언이라는 두 마리의 토끼를 잡을 수 있는지에 대해서 살펴보았습니다.
다음 포스팅에서는 Zod의 스키마를 작성하는 방법에 대해서 좀 더 상세히 알아보도록 하겠습니다. 언어에 종속되지 않는 범용 표준으로 데이터 구조를 정의하고 싶다면 JSON Schema도 살펴보세요.
Zod 관련 포스팅은 Zod 태그를 통해서 쉽게 만나보세요!
This work is licensed under
CC BY 4.0