귀여운 눈높이에서 작성된, 🐰

하루 한 걸음씩, 성장 하는 중 입니다 🫶🏻

Studying/React

리액트 - input은 문자열

creamymood 2025. 6. 24. 12:55


1. HTML의 input은 무조건 "문자열(string)"을 다룬다

브라우저에서 우리가 쓰는 <input /> 태그는,
사용자가 어떤 걸 입력해도 결과는 무조건 string으로 나온다

 

<input type="text" />
<input type="number" />
<input type="password" />
<input type="email" />

위의 어떤 type을 쓰든 간에,
event.target.value로 받아오는 값은 무조건 string

 

 예시

<input
  type="number"
  onChange={(e) => {
    console.log(typeof e.target.value); // 👉 항상 "string"
    console.log(e.target.value);        // 👉 예: "123"
  }}
/>

사용자가 123이라고 쳐도, "123"이라는 문자열로 들어옴
숫자로 보이지만 실제론 글자

 

 그래서 우리가 하는 일

  • 사용자가 입력한 value는 string으로 받고
  • 그게 숫자처럼 생겼으면 → parseInt()나 Number()로 우리가 직접 숫자로 바꿔주는 거야

 요약표

사용자가 입력한 값 브라우저가 주는 값 실제 타입 우리가 해야 할 일

123 "123" string 숫자가 필요하면 변환해야 함
20001004 "20001004" string parseInt("20001004") 필요

 



"HTML 인풋은 무조건 string인데, 타입스크립트에서 타입을 지정하는 건 왜? 무슨 의미야?"
TypeScript에서 아래처럼 value: string으로 타입을 명시하는 이유는 크게 두 가지야:

 1. 개발자가 실수하는 걸 막기 위해서

<Input value={123} /> // ❌ 에러 발생
  • 여기서 123은 number 타입이야. TypeScript는 이걸 보고 에러를 내줘.
  • 왜냐하면 Input 컴포넌트가 value: string만 받는다고 약속했기 때문이야.
  • 이런 식으로 숫자, 객체, 배열 같은 예상치 못한 타입이 들어오는 걸 미리 방지할 수 있어.

 

2. onChange 함수의 일관성을 유지하기 위해

onChange: (value: string) => void
  • 인풋의 값은 문자열인데, 만약 value가 숫자일 수도 있다고 하면 onChange도 (value: number | string) => void처럼 복잡해져.
  • 하지만 value가 무조건 string이라는 보장이 있으면, onChange도 심플하게 string만 다루면 되니까 코드가 더 안전하고 깔끔해져.

 그런데 실제로는?

브라우저가 인풋 값을 "123"처럼 문자열로 처리해주긴 하지만, 우리가 실수로 number를 value로 넘기면 렌더링은 되지만 경고나 예기치 못한 결과가 발생할 수 있어.
그래서 아예 타입 차원에서 차단해주는 게 더 안전한 거야.

 

 정리하면

"브라우저가 알아서 숫자도 string으로 바꿔주긴 해.
하지만 TypeScript에선 명확히 value: string으로 제한해서
실수를 줄이고, onChange 같은 로직도 안정적으로 만들 수 있어!"

 

 

🧸 요약

브라우저:

"나는 string밖에 못 줘"

타입스크립트:

"그래! 그럼 너 이게 string이란 거 확실히 알고 써. 실수하면 내가 막아줄게!"

 



이제 string인데 숫자나 특수기호가 왜 들어갈 수 있지? 하는 궁금증이 생긴 거지?

아주 쉽게, 완전 기초부터 풀어줄게.
이걸 이해하면 문자열(string)이 어떤 건지 더 확실히 감 잡을 수 있어!

 먼저, 문자열(string)이란?

문자열은 글자 하나하나의 나열이야.
그 안에 들어갈 수 있는 건 숫자든, 알파벳이든, 특수기호든 상관없어!

"123"
"hello"
"!@#"
"abc123@naver.com"

위에 있는 건 전부 다 string 타입이야.

 "숫자"가 들어왔다고 해서 그 값이 숫자(Number)인 건 아니야

예를 들어:

const value = "123";
console.log(typeof value); // 👉 string

비록 123이라는 숫자처럼 생겼어도,
따옴표로 묶여 있으면 그냥 문자야.
즉, '1', '2', '3'이 나란히 있는 "글자 덩어리"일 뿐이야.

 특수기호도 마찬가지야

const email = "abc@naver.com"; // @는 문자 중 하나
console.log(typeof email); // 👉 string

@, !, #, $ 같은 것도 그냥 글자로 취급되는 거야.
그냥 우리가 보기엔 "기호"처럼 생겼지만, 컴퓨터는 이것도 "문자 1개"라고 생각해.

 input은 모두 문자열(string)로 입력값을 받아

즉, input에 아래처럼 쳐도:

<input type="text" />

사용자가 "abc123@naver.com"이라고 쓰면,
value는 "abc123@naver.com" — 문자열이 되는 거야.

 그럼 숫자가 필요할 땐?

그때는 우리가 string → number로 변환해줘야 해:

const str = "123";
const num = parseInt(str); // 👉 123 (숫자)

 

정리: string 안에는 뭐든 들어올 수 있어

"123" string 숫자처럼 생긴 문자열
"@#$%^" string 특수문자로 된 문자열
"abc123@naver.com" string 이메일 형식이지만 여전히 문자열
"true" string 불리언처럼 보이지만 그냥 글자

→ 이건 전부 문자열(string)로 처리됨!


✨ 마무리 요약

  • input 값은 무조건 string
  • 숫자, 특수기호, 영어 다 포함할 수 있어
  • 진짜 숫자 계산하려면 → parseInt, Number()로 변환 필요
  • 타입스크립트에서는 value: string으로 지정하는 게 맞아!


"그럼 유효성 검사는 어떻게 해? 문자열인데 숫자로 바꿔서 해?"
→ 이건 값의 형태에 따라 달라, 그래서 예시와 함께 하나씩 쉽게 설명할게!

 

유효성 검사의 핵심

입력값이 어떤 "형식"이나 "규칙"을 만족하는지 확인하는 과정
(숫자로 바꾸는 건 필요할 때만!)

 숫자만 입력해야 하는 경우

예: 인증번호, 생년월일 등

const isValidCode = /^\d{6}$/.test(validCode); 
// 숫자 6자리만 허용 (예: 123456)

 여기서 숫자로 변환하지 않아도 돼!
왜냐하면 이건 문자열이 숫자로만 구성돼 있는지만 검사하는 거니까.

이메일 검증

const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

 이건 @가 포함돼 있고 형식이 맞는지 체크
숫자 변환과는 전혀 관계 없어!

비밀번호 복잡도 (영문+숫자+특수문자)

const isValidPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,15}$/.test(password);

이건 문자열 안에

  • 영문 소문자 하나 이상
  • 영문 대문자 하나 이상
  • 숫자 하나 이상
  • 특수기호 하나 이상
  • 총 8~15자

이 조건들을 확인하는 거고,
당연히 string 그대로 검사야.


정말 숫자 연산이 필요한 경우만 변환!

const ageString = "20";
const age = parseInt(ageString);
if (!isNaN(age) && age >= 18) {
  // 성인
}

이런 경우는 "숫자로서의 의미"가 중요하니까 변환하는 거야.


 정리표

검사 대상 예시 숫자로 변환 필요?
이메일 example@gmail.com ❌ No
비밀번호 조건 영문+숫자+기호 ❌ No
인증번호 6자리 "123456" ❌ No
나이 계산, 생년월일 연산 "20001004" → 계산할 때 ✅ Yes

 마무리 요약

  • 유효성 검사는 대부분 string 상태에서 검사
  • 정규식 (/.test()) 많이 사용
  • 진짜 숫자로 연산이 필요할 때만 parseInt, Number() 사용

 


결론

 

그니까, 인풋 자체는 string 타입이 들어오는데..(어떤 데이터가 들어와도 string이라고 처리 되는데)

굳이 타입을 string이라고 한번 더 지정 해주는 이유는.. 혹시 모를 실수 방지와, onchange 함수의 일관성 때문!