DEV/TypeScript

React에 TypeScript 적용하기 - 3. 기본 Hook 타입 적용하기

develop-ch94 2026. 8. 4. 11:28

1. useState 타입 정의

React의 useState는 제네릭을 통해 상태의 타입을 지정할 수 있음
import React, { useState } from 'react';

function BasicComponent() {
  const [count, setCount] = useState<number>(0);
  const [name, setName] = useState<string>('');
  const [isVisible, setIsVisible] = useState<boolean>(false);
  const [age, setAge] = useState<number>(25);
  const [message, setMessage] = useState<string>('Hello');
  
  return (
    <div>
      <p>Count: {count}</p>
      <p>Name: {name}</p>
      <p>Visible: {isVisible ? 'Yes' : 'No'}</p>
    </div>
  );
}

 

복잡한 타입 사용

interface User {
  id: number;
  name: string;
  email: string;
}

interface FormData {
  username: string;
  password: string;
  rememberMe: boolean;
}

function UserComponent() {
  // 객체 타입
  const [user, setUser] = useState<User | null>(null);
  
  // 배열 타입
  const [users, setUsers] = useState<User[]>([]); // User[]는 빈배열 []도 포함
  
  // 복잡한 폼 데이터
  const [formData, setFormData] = useState<FormData>({
    username: '',
    password: '',
    remamberMe: false;
  });
  
  // 유니온 타입
  const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading');
  
  const handleUserUpdate = (newUser: User) => {
    setUser(newUser);
  };
  
  const handleFormChange = (field: keyof FormData, value: string | boolean) => {
    setFormData(prev => ({
      ...prev,
      [field]: value
    }));
  };
  
  return (
    <div>
      <p>User: {user?.name}</p>
      <p>Status: {status}</p>
      <p>Users count: {users.length}</p>
    </div>
  );
}

 

useState 고급 패턴

// 함수형 업데이트와 타입
function CounterComponent() {
  const [count, setCount] = useState<number>(0);
  
  const increment = () => {
    // 함수형 업데이트 - 타입 안전
    setCount(prev => prev + 1); // prev는 number로 추론
  };
  
  const reset = () => {
    setCount(0);
  };
  
  return (
    <div>
      <span>{count}</span>
      <button onClick={increment}>+1</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

// 커스텀 훅과 useState
function useCounter(initialValue: number = 0) {
  const [count, setCount] = useState<number>(initialValue);
  
  const increment = () => setCount(prev => prev + 1);
  const decrement = () => setCount(prev => prev - 1);
  const reset = () => setCount(initialValue);
  
  return { count, increment, decrement, reset };
}

2. useRef 타입 정의

DOM 요소 참조

import React, { useRef, useEffect } from 'react';

function DOMRefComponent() {
  // HTML 요소별 구체적인 타입 지정
  const inputRef = useRef<HTMLInputElement>(null);
  const divRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  
  useEffect(() => {
    // null 체크 후 안전하게 사용
    if (inputRef.current) {
      inputRef.current.focus(); // HTMLInputElement 메소드 사용 가능
    }
    
    if (divRef.current) {
      divRef.current.scrollTop = 0; // HTMLDivElement 속성 접근
    }
  }, []);
  
  const handleButtonClick = () => {
    if (inputRef.current) {
      console.log('Input value:', inputRef.current.value);
      inputRef.current.select(); // 텍스트 전체 선택
    }
  };
  
  return (
    <div ref={divRef}>
      <input
        ref={inputRef}
        type="text"
        placeholder="Type here..."
      />
      <button ref={buttonRef} onClick={handleButtonClick}>
        Focus Input
      </button>
      <canvas ref={canvasRef} width={300} height={200} />
    </div>
  );
}

 

값 저장용 useRef

function ValueRefComponent() {
  // 값 저장용
  const countRef = useRef<number>(0); // React.MutableRefObject<number>
  const timerRef = useRef<number | null>(null); // React.MutableRefObject<number | null>
  const userRef = useRef<User | null>(null); // React.MutableRefObject<User | null>
  
  // 함수 저장
  const callbackRef = useRef<((data: string) => void) | null>(null);
  
  useEffect(() => {
    // 타이머 ID 저장
    timerRef.current = window.setInterval(() => {
      countRef.current += 1;
      console.log('Count:', countRef.current);
    }, 1000);
    나변수 = "20";
    return () => {
      if (timerRef.current) {
        clearInterval(timerRef.current);
      }
    };
  }, [a]);
  
  const updateCallback = (fn: (data: string) => void) => {
    callbackRef.current = fn;
  };
  
  return <div>Check console for timer updates</div>;
}

3. useParams 타입 정의

import { useParams } from 'next/navigation';

// URL: /user/123
function UserProfile() {
  // 타입 지정 없이 사용 (권장하지 않음)
  const params = useParams(); // { [key: string]: string | undefined }
  const userId = params.id; // string | undefined
  
  return <div>User ID: {userId}</div>;
}

// 타입 안전한 방법
interface UserParams {
  id: string;
}

// src/app[id]/page.tsx
function UserProfileTyped() {
  const { id } = useParams<UserParams>(); // id: string | undefined
  
  return <div>User ID: {id}</div>;
}