Skip to Content
페이먼츠 미션1단계 안티패턴anti-03. Number()/isNaN() 검증의 함정

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 리뷰:

isNotNumberNumber() 강제 변환은 숫자 검증을 완전히 보장하지 못합니다.”

PR #514 “Number 기반 숫자 검증 사용” 으로 같은 신호.

리뷰어 피드백 (실제 인용)

  • PR #497  CardValidator.ts:5“Number(value) 기반 체크는 ‘1e2’, ’+’, 공백 같은 값을 통과” → 숫자 문자 검증 좁히기 제안
  • PR #505  useCardNumber.tsx:17isNotNumber() 함수는 단순히 isNaN(Number(value))
  • PR #507  useCardCvc.tsx:17Number() 기반 검증은 “숫자 문자열만 허용” 요구를 우회시킵니다.”
  • PR #511  utils.ts:3“숫자 문자열 검증에서 공백이 통과하는 이슈를 발견하였어요”
  • PR #512  validate.ts:70“숫자 판별이 너무 느슨합니다.” → digit-only 정규식 검증 제안

코드 리뷰 자동화 봇(CodeRabbit )이 5개 이상 PR에서 거의 같은 코멘트를 달았다는 점이 흥미롭다.

type="number" 도 함정 — 함께 따라오는 신호

PR #510 의 페어가 직접 PR body에 적은 회고:

maxLength props를 받아 입력 길이를 제한하려 했는데, input의 type="number"에서는 maxLength가 동작하지 않는 문제가 있었습니다. 두 제약 중 maxLength를 선택하고 type="text"로 변경한 뒤, 숫자만 입력되도록 제한 로직을 걸었습니다.”

PR #520 PR #524 는 README에 이 결정을 명시적으로 기록한다:

type="number"e, +, -, . 등의 입력을 허용하고, 앞자리 0 보존이 안 되는 등의 문제가 있어 카드 입력에는 적합하지 않을 수 있다.”

type="text" + inputMode="numeric" + onChange 필터링 조합이 일부 PR에서 정착되어 가는 결정.

토론 질문

  1. Number('1e2'), Number(' '), Number('+'), Number('') 의 결과는 각각 무엇인가? 무엇이 의외였는가?
  2. “숫자 문자열만 허용” 을 정확히 표현하려면 어떤 도구가 필요한가? 정규식? 자릿수 검사? 다른 방법?
  3. type="number" vs type="text" + inputMode="numeric" — 둘의 모바일 키패드 / 키보드 입력 제한 / 복사·붙여넣기 동작 은 어떻게 다른가?

연관 카드

Last updated on