// 에러가 발생한 코드
const formValidation = z.object({
use_state: z
.string({ required_error: "사용여부를 선택해주세요." })
.trim()
.min(1, { message: "사용여부를 선택해주세요." }),
use_purpose: z
.string({ required_error: "사용용도를 입력해주세요." })
.trim()
.min(1, { message: "사용용도를 입력해주세요." }),
product_name: z
.string({ required_error: "제품명을 입력해주세요." })
.trim()
.min(1, { message: "제품명을 입력해주세요." }),
manufacture: z
.string({ required_error: "제조사를 입력해주세요." })
.trim()
.min(1, { message: "제조사를 입력해주세요." }),
monthly_usage: z
.number({ required_error: "월사용량을 입력해주세요." })
.min(1, { message: "월사용량을 입력해주세요." }),
unit: z
.string({ required_error: "단위를 입력해주세요." })
.trim()
.min(1, { message: "단위를 입력해주세요." }),
renewal_on: z
.string({ required_error: "MSDS 개정일자를 입력해주세요." })
.trim()
.min(1, { message: "MSDS 개정일자를 입력해주세요." }),
});
// 정상적으로 작동한 코드
const formValidation = z.object({
use_state: z
.string({ message: "사용여부를 선택해주세요." })
.trim()
.min(1, { message: "사용여부를 선택해주세요." }),
use_purpose: z
.string({ message: "사용용도를 입력해주세요." })
.trim()
.min(1, { message: "사용용도를 입력해주세요." }),
product_name: z
.string({ message: "제품명을 입력해주세요." })
.trim()
.min(1, { message: "제품명을 입력해주세요." }),
manufacture: z
.string({ message: "제조사를 입력해주세요." })
.trim()
.min(1, { message: "제조사를 입력해주세요." }),
monthly_usage: z
.number({ message: "월사용량을 입력해주세요." })
.min(1, { message: "월사용량을 입력해주세요." }),
unit: z
.string({ message: "단위를 입력해주세요." })
.trim()
.min(1, { message: "단위를 입력해주세요." }),
renewal_on: z
.string({ message: "MSDS 개정일자를 입력해주세요." })
.trim()
.min(1, { message: "MSDS 개정일자를 입력해주세요." }),
});
에러 발생 이유
required_error는 해당 필드가 undefined 또는 null일 때만 작동합니다. 그런데 앞서 해당 필드를 빈 문자열("")로 초기화했었기 때문에, required_error는 작동하지 않았던 것입니다.
그 이유는 빈 문자열("")은 값이 존재하는 것으로 간주되어 required_error에서 트리거되지 않기 때문입니다.
초기값을 빈 문자열로 설정했을 경우에는, Zod의 min(1)과 같은 최소 길이 검사를 사용하면 됩니다. min(1)은 문자열의 길이가 1 이상이어야 한다는 조건이므로, 빈 문자열이 입력된 경우 에러가 발생하게 된다
그런데 처음에 required_error 와 min(1)을 모두 사용했었음에도 빈 문자열로 에러 처리가 안된 이유?
required_error가 작동하지 않았으니 min(1)에서라도 트리거되어서 alert 창이 떴어야 하는게 아닌가?
라고 생각하실 수 있지만
Zod 내부에서 에러처리의 우선순위에 문제가 발생했을 수도 있습니다.
즉 required_error가 트리거되지 않았기에 그 다음으로 존재하는 min(1)까지 도달하지 못해서 에러 핸들링에 혼선이 생겼을 가능성이 존재하는 겁니다.
해결책은 ??
1 ) .string({message : “~” }) … {message : “~” }
unit: z
.string({ message: "단위를 입력해주세요." })
.trim()
.min(1, { message: "단위를 입력해주세요." }),
첫번째 message
필드가 아예 존재하지 않거나, 값이 undefined 또는 null이거나 타입이 문자열이 아닌 경우에 이 메시지가 표시됩니다
→ 타입 검증 및 빈 값 자체를 막아줍니다. 입력이 아예 없거나 잘못된 타입일 때 에러를 발생시킵니다.
두번째 message
필드가 빈 문자열이거나 문자열의 길이가 지정된 최소 길이(여기서는 1)보다 짧은 경우에 이 메시지가 표시됩니다
→ 빈 문자열에 대한 추가적인 길이 검증을 제공합니다
💡 둘을 함께 쓰면, 타입 검증과 값 검증을 모두 커버할 수 있습니다
2 ) .string() … {message : “~” }
unit: z
.string()
.trim()
.min(1, { message: "단위를 입력해주세요." }),
타입 필드 안에 message가 공백이라면 입력값이 undefined, null, 숫자, 배열 등 문자열이 아닌 타입일 경우에는 기본적으로 타입 에러를 발생시킵니다.
이때 따로 에러 메시지를 지정하지 않으면 Zod의 기본 에러 메시지가 출력됩니다. → “expected string, but got number”
그럼 .string() 으로 하는게 맞는지, 아니면 .string({message:"~"})로 하는게 맞는지?
Chat-GPT 曰
1. .string()만 사용하는 경우:
unit: z
.string()
.trim()
.min(1, { message: "단위를 입력해주세요." })
이 형태는 기본적인 타입 검증을 수행하면서, 문자열 타입 에러에 대한 기본 메시지를 그대로 사용합니다.
- 타입 검증에서 발생하는 에러 메시지가 기본으로 제공되며, 따로 커스터마이징할 필요가 없으면 이 방법으로 충분합니다.
- 예를 들어, unit 필드가 문자열이 아닌 경우, 기본적으로 "Expected string, received undefined"와 같은 Zod의 기본 에러 메시지가 표시됩니다.
2. .string({ message: "메시지" })를 사용하는 경우:
unit: z
.string({ message: "단위는 문자열로 입력해주세요." })
.trim()
.min(1, { message: "단위를 입력해주세요." })
이 형태는 타입 검증에서 발생하는 에러 메시지를 커스터마이징할 때 유용합니다.
- 만약 문자열 타입이 아닌 값이 들어왔을 때, 커스텀 에러 메시지를 보여주고 싶다면 이 방법을 사용해야 합니다.
- 예를 들어, 숫자나 다른 타입의 값이 들어왔을 때 "단위는 문자열로 입력해주세요."라는 메시지를 사용자에게 보여줄 수 있습니다.
정리:
- .string(): 타입 검증에서 기본 메시지를 사용하고 싶다면 이걸 사용하세요.
- .string({ message: "메시지" }): 문자열이 아닌 다른 타입의 값이 들어왔을 때 커스텀 메시지를 보여주고 싶다면 이걸 사용하세요.
따라서, 타입 에러 메시지를 커스터마이징할 필요가 없으면 .string()만 써도 충분하고, 에러 메시지를 사용자에게 좀 더 친절하게 제공하고 싶다면 .string({ message: "메시지" })를 사용하세요.
'💻 프론트엔드 : Frontend > Javascript | Typescript' 카테고리의 다른 글
헷갈리는 Lodash import 구문 : import * as _는 되고 import _는 안 되는 이유 (0) | 2025.06.24 |
---|---|
validation library 비교 (zod, class-validator, joi) (1) | 2024.10.11 |
readExcelFile로 병합된 셀을 잘 받아오는 법 (0) | 2024.10.04 |
브라켓[]을 활용한 동적 라우팅 (0) | 2024.09.06 |