anti-03. Number() / isNaN() 기반 숫자 검증의 함정
빈도: 25건 중 6+건 — “숫자 문자열만 허용” 이라는 명세를 만족시키는 가장 직관적인 방법이지만, 통과하지 말아야 할 입력이 통과한다.
패턴 한 줄
Number(value)가 NaN이 아니면 “숫자 문자열” 로 보고 통과시킨다. 하지만 JavaScript의 Number()는 '1e2', '+', '', 공백 문자열, .5 등도 유효한 숫자로 변환한다.
AS-IS 코드 (8기 PR 발췌)
🔍 읽기 전에
“내 검증 함수에
'1e2'또는 공백 문자 한 글자(' ')를 넣어보자.true가 반환되는가,false가 반환되는가?”
사례 A — Number(value) 직접 사용
PR #497 — CardValidator.ts
리뷰어 코멘트가 한 줄로 이 패턴을 짚었다:
“Number(value) 기반 체크는
'1e2','+', 공백 같은 값을 통과합니다.”
사례 B — isNaN(Number(value))로 감싸기
PR #505 — useCardNumber.tsx
// src/hooks/useCardNumber.tsx
const isNotNumber = (value: string) => isNaN(Number(value));isNotNumber('')은 false (NaN 아님). isNotNumber('1e2')도 false. isNotNumber(' ')도 false — 공백 한 글자가 숫자가 아닌 것이 아니라고 판정된다.
사례 C — 같은 검증을 length만 다르게 반복
PR #510 — getCVCNumberErrorMessage.ts, isMonthMatch.ts
// src/utils/getCVCNumberErrorMessage.ts
// CVC가 숫자가 아니어도 길이 3이면 검증을 통과한다. (리뷰어 지적)사례 D — 핵심 인용
PR #507 util.ts:40 리뷰:
“
isNotNumber의Number()강제 변환은 숫자 검증을 완전히 보장하지 못합니다.”
PR #514 도 “Number 기반 숫자 검증 사용” 으로 같은 신호.
리뷰어 피드백 (실제 인용)
- PR #497
CardValidator.ts:5— “Number(value) 기반 체크는 ‘1e2’, ’+’, 공백 같은 값을 통과” → 숫자 문자 검증 좁히기 제안 - PR #505
useCardNumber.tsx:17— “isNotNumber()함수는 단순히isNaN(Number(value))” - PR #507
useCardCvc.tsx:17— “Number()기반 검증은 “숫자 문자열만 허용” 요구를 우회시킵니다.” - PR #511
utils.ts:3— “숫자 문자열 검증에서 공백이 통과하는 이슈를 발견하였어요” - PR #512
validate.ts:70— “숫자 판별이 너무 느슨합니다.” → digit-only 정규식 검증 제안
코드 리뷰 자동화 봇(CodeRabbit )이 5개 이상 PR에서 거의 같은 코멘트를 달았다는 점이 흥미롭다.
type="number" 도 함정 — 함께 따라오는 신호
PR #510 의 페어가 직접 PR body에 적은 회고:
“
maxLengthprops를 받아 입력 길이를 제한하려 했는데, input의type="number"에서는maxLength가 동작하지 않는 문제가 있었습니다. 두 제약 중maxLength를 선택하고type="text"로 변경한 뒤, 숫자만 입력되도록 제한 로직을 걸었습니다.”
PR #520 과 PR #524 는 README에 이 결정을 명시적으로 기록한다:
“
type="number"는e,+,-,.등의 입력을 허용하고, 앞자리0보존이 안 되는 등의 문제가 있어 카드 입력에는 적합하지 않을 수 있다.”
→ type="text" + inputMode="numeric" + onChange 필터링 조합이 일부 PR에서 정착되어 가는 결정.
토론 질문
Number('1e2'),Number(' '),Number('+'),Number('')의 결과는 각각 무엇인가? 무엇이 의외였는가?- “숫자 문자열만 허용” 을 정확히 표현하려면 어떤 도구가 필요한가? 정규식? 자릿수 검사? 다른 방법?
type="number"vstype="text" + inputMode="numeric"— 둘의 모바일 키패드 / 키보드 입력 제한 / 복사·붙여넣기 동작 은 어떻게 다른가?
연관 카드
- Q7 — input 제약 — maxLength vs type=number — 같은 주제, 고민 관점
- Q5 — 검증과 에러 책임




