zod is a TypeScript-first schema declaration and validation library. -Zod Docs
zod는 공식 문서에 나와있듯이 스키마 선언 및 유효성 검사 라이브러리이다.
지금부터 이 zod에 대해 파헤쳐보자.
zod가 필요한 이유는 TypeScript의 한계 때문이다.
TypeScript는 컴파일 시점에서의 타입에러만 잡아낼 수 있고 런타임 단계에서의 타입 에러는 어쩔 수가 없다. 왜냐면 런타임 단계에서 작동되는 것은 JavaScript이기 때문이다.
또 잘 알고있듯이 TypeScript는 number 타입만 입력받도록 강제하는 것은 가능하다.
하지만 원하는 문자열이나 원하는 숫자 범위를 강제하거나 number타입의 정수/실수 구분은 불가능하다.
이러한 TypeScript의 한계 때문에 zod라이브러리를 사용한다.
스키마(schema)라는 단어는 형태 , 모양 , 모양 또는 계획 을 의미 하는 그리스어 skhēma 에서 유래했다.
여기서의 스키마란 데이터의 형태 및 구조라고 할 수 있다. 한 남성의 신상 정보에 대해 zod를 통해 스키마를 정의해 보겠다.
import { z } from "zod";
const Man = z.object({
name: z.string(),
height: z.number(),
age: z.number(),
phoneNum: z.string(),
homePhoneNum: z.string().optional(),
isCompletedMilitaryService: z.boolean(),
});
이렇게 zod를 통해 나에대한 정보를 객체 형식으로 나타내보았다.
zod 문법에 대해 배운적이 없더라도 바로 이해할 수 있을 정도로 직관적이다.
이제 이를 통해 유효성 검증을 하는 방법에 대해 알아보자.
Man.parse({
name: "김진영",
height: 180,
age: 23,
phoneNum: "01000000000",
isCompletedMilitaryService: true,
});
// 유효성 검증 통과
// return {
// name: "김진영",
// height: 180,
// age: 23,
// phoneNum: "01000000000",
// isCompletedMilitaryService: true,
//}
Man.parse({
name: "아오키지",
height: 180,
age: "아이스에이지",
phoneNum: "01000000000",
isCompletedMilitaryService: true,
});
// 유효성 검증 실패
// throws Error
유효성 검증 또한 간단하다. parse
를 통해 진행하면 된다.
첫 번째의 경우엔 유효성 검증을 통과했기 때문에 그대로 입력값을 return하고 두 번째같은 경우엔 잘못된 값이 들어왔기 때문에 유효성 검증에 실패하여 Error를 throw한다.
특히 이 Error는 정확히 어떤 부분에서 왜 검증이 실패하였는지에 대한 정보가 들어있기 때문에 매우 유용하다. 위 유효성 검증 실패 예시는 이러한 오류가 뜬다.
[
{
"code": "invalid_type",
"expected": "number",
"received": "string",
"path": [
"age"
],
"message": "Expected number, received string"
}
]
parse
뿐만 아니라 safeParse
라는 기능도 있는데, 이 기능은 공식문서를 참고하면 좋을 듯 하다. 공식문서 safeParse 바로가기
또 zod는 스키마를 기준으로 타입을 추론할 수 있다.
이 기능을 통해 타입을 따로 작성할 필요가 없어진다. 아래 예시를 살펴보자.
import { z } from "zod";
const Man = z.object({
name: z.string(),
height: z.number(),
age: z.number(),
phoneNum: z.string(),
homePhoneNum: z.string().optional(),
isCompletedMilitaryService: z.boolean(),
});
type ManType = z.infer<typeof Man>;
const processMan = (man : ManType) => {
Man.parse(man); // 유효성 검증
// 사용자 처리 로직
}
이처럼 정의한 스키마로부터 타입을 뽑아내 따로 작성하지 않고도 타입을 정의할 수 있다.
import { z } from "zod";
// primitive values
z.string();
z.number();
z.bigint();
z.boolean();
z.date();
z.symbol();
// empty types
z.undefined();
z.null();
z.void(); // accepts undefined
// catch-all types
// allows any value
z.any();
z.unknown();
// never type
// allows no values
z.never();
잘 읽었습니다
한번에 이해 될 정도로 명확한 설명 감사합니다.