React + TypeScript 도입과 패턴
2025. 4. 2. 15:29ㆍFrameworks/React
React + TypeScript 도입과 패턴
TypeScript란 무엇인가요?
TypeScript는 JavaScript에 **타입(Type)**을 추가한 언어입니다. 쉽게 말해 변수, 함수, 객체가 어떤 형태인지 미리 정해놓고 사용하는 방식입니다.
왜 React에 TypeScript를 사용해야 할까요?
- 실수 예방: 코드를 작성할 때 실수를 미리 잡아줍니다
- 편리한 자동완성: 어떤 속성이 있는지 자동으로 알려줍니다
- 유지보수 용이: 나중에 코드를 수정할 때도 쉽게 이해할 수 있습니다
React + TypeScript 시작하기
새 프로젝트 생성하기
# TypeScript로 React 프로젝트 시작하기
npx create-react-app my-app --template typescript
기존 프로젝트에 추가하기
# 기존 프로젝트에 TypeScript 추가하기
npm install --save typescript @types/node @types/react @types/react-dom
기본적인 타입 패턴
1. Props 타입 지정하기
// 기본 방식
type ButtonProps = {
text: string;
onClick: () => void;
color?: string; // ? 는 선택적(optional) 속성
};
function Button({ text, onClick, color = 'blue' }: ButtonProps) {
return (
<button onClick={onClick} style={{ backgroundColor: color }}>
{text}
</button>
);
}
2. 상태(State) 타입 지정하기
// useState에 타입 지정하기
import { useState } from 'react';
function Counter() {
// number 타입의 상태 선언
const [count, setCount] = useState<number>(0);
// 객체 타입의 상태 선언
const [user, setUser] = useState<{name: string; age: number}>({
name: '',
age: 0
});
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
3. 이벤트 핸들러 타입 지정하기
import { ChangeEvent, FormEvent } from 'react';
function LoginForm() {
// 폼 제출 이벤트 타입 지정
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
// 폼 제출 로직
};
// 입력 변경 이벤트 타입 지정
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" onChange={handleChange} />
<button type="submit">로그인</button>
</form>
);
}
유용한 TypeScript 패턴
1. 인터페이스 확장하기
// 기본 인터페이스
interface BaseProps {
className?: string;
style?: React.CSSProperties;
}
// 확장된 인터페이스
interface ButtonProps extends BaseProps {
text: string;
onClick: () => void;
}
function Button({ text, onClick, className, style }: ButtonProps) {
return (
<button onClick={onClick} className={className} style={style}>
{text}
</button>
);
}
2. 유니온 타입 활용하기
// 버튼 크기를 지정하는 유니온 타입
type ButtonSize = 'small' | 'medium' | 'large';
type ButtonVariant = 'primary' | 'secondary' | 'danger';
type ButtonProps = {
size: ButtonSize;
variant: ButtonVariant;
label: string;
};
function Button({ size, variant, label }: ButtonProps) {
let padding;
let backgroundColor;
// size에 따라 다른 스타일 적용
if (size === 'small') padding = '4px 8px';
else if (size === 'medium') padding = '8px 16px';
else padding = '12px 24px';
// variant에 따라 배경색 지정
if (variant === 'primary') backgroundColor = 'blue';
else if (variant === 'secondary') backgroundColor = 'gray';
else backgroundColor = 'red';
return (
<button style={{ padding, backgroundColor }}>
{label}
</button>
);
}
3. Children 타입 지정하기
import { ReactNode } from 'react';
type CardProps = {
title: string;
children: ReactNode; // JSX 요소나 문자열 등 모든 자식 요소 허용
};
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-content">{children}</div>
</div>
);
}
// 사용 예시
function App() {
return (
<Card title="환영합니다">
<p>카드 내용입니다.</p>
<button>자세히 보기</button>
</Card>
);
}
고급 TypeScript 패턴
1. 제네릭 컴포넌트 만들기
// 제네릭을 사용한 재사용 가능한 목록 컴포넌트
type ListProps<T> = {
items: T[];
renderItem: (item: T) => ReactNode;
};
function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
// 사용 예시
function App() {
const users = [
{ id: 1, name: '김철수' },
{ id: 2, name: '이영희' }
];
return (
<List
items={users}
renderItem={(user) => <span>{user.name}</span>}
/>
);
}
2. 타입 가드 활용하기
// 서로 다른 타입의 항목을 처리하는 경우
type TextItem = {
type: 'text';
content: string;
};
type ImageItem = {
type: 'image';
url: string;
alt: string;
};
type ContentItem = TextItem | ImageItem;
function ContentRenderer({ item }: { item: ContentItem }) {
// 타입 가드를 사용하여 올바른 렌더링 로직 적용
if (item.type === 'text') {
return <p>{item.content}</p>;
} else {
return <img src={item.url} alt={item.alt} />;
}
}
실전 팁과 트릭
1. API 응답 타입 정의하기
// API 응답 타입 정의
interface User {
id: number;
name: string;
email: string;
}
// 데이터를 가져오는 훅
function useUsers() {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then((data: User[]) => {
setUsers(data);
setLoading(false);
});
}, []);
return { users, loading };
}
2. 타입 정의 파일 분리하기
// types.ts 파일에 타입 정의 모음
export interface User {
id: number;
name: string;
email: string;
}
export interface Post {
id: number;
title: string;
content: string;
userId: number;
}
export type CommentType = {
id: number;
postId: number;
text: string;
author: string;
};
3. 커스텀 훅에 타입 적용하기
import { useState, useEffect } from 'react';
// 제네릭을 활용한 재사용 가능한 데이터 가져오기 훅
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('네트워크 응답이 올바르지 않습니다');
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error instanceof Error ? error : new Error('알 수 없는 오류'));
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// 사용 예시
interface Todo {
id: number;
title: string;
completed: boolean;
}
function TodoList() {
const { data, loading, error } = useFetch<Todo[]>('https://jsonplaceholder.typicode.com/todos');
if (loading) return <div>로딩 중...</div>;
if (error) return <div>오류: {error.message}</div>;
if (!data) return <div>데이터가 없습니다</div>;
return (
<ul>
{data.map(todo => (
<li key={todo.id}>
{todo.completed ? '✅' : '❌'} {todo.title}
</li>
))}
</ul>
);
}
요약
- TypeScript는 React 개발에 안정성과 생산성을 더해줍니다
- 기본적인 패턴으로 Props, State, 이벤트 타입 지정하기
- 고급 패턴으로 인터페이스 확장, 유니온 타입, 제네릭 활용하기
- 실제 개발에서는 API 응답 타입 정의, 타입 파일 분리 등의 방법 사용하기
'Frameworks > React' 카테고리의 다른 글
React 성능 분석 실전 (0) | 2025.04.02 |
---|---|
테스트 전략 (Jest, RTL, Cypress) (0) | 2025.04.02 |
React 애플리케이션 성능 최적화 (0) | 2025.04.01 |
React 폼 관리와 유효성 검사 (0) | 2025.04.01 |
React 컴포넌트 스타일링 방법 (0) | 2025.04.01 |