Search for a command to run...

안녕하세요, 프론트엔드 개발자 여러분! 오늘은 현대 웹 개발에서 거의 표준 조합으로 자리 잡은 React와 TypeScript에 대해 이야기해보려고 합니다. 순수 JavaScript(바닐라 JS)로 React 프로젝트를 진행하다 보면, 프로젝트 규모가 커질수록 예상치 못한 타입 관련 버그 때문에 골머리를 앓았던 경험, 다들 한 번쯤 있으시죠? 바로 이 지점에서 TypeScript가 구원투수로 등판합니다.
TypeScript는 JavaScript에 정적 타입을 추가한 슈퍼셋(Superset) 언어입니다. 코드를 실행하기 전, 즉 컴파일 단계에서 타입 오류를 미리 잡아내어 런타임 에러를 획기적으로 줄여줍니다. React와 함께 사용하면 다음과 같은 강력한 이점들을 얻을 수 있습니다.
처음에는 타입을 일일이 정의하는 것이 번거롭게 느껴질 수 있지만, 이 작은 노력이 장기적으로는 훨씬 더 안정적이고 견고한 애플리케이션을 만드는 밑거름이 됩니다.
가장 쉬운 방법은 Create React App(CRA)의 TypeScript 템플릿을 사용하는 것입니다. 터미널에 다음 명령어를 입력해보세요.
npx create-react-app my-app --template typescript
이 한 줄이면 TypeScript, ESLint, 그리고 React를 위한 각종 설정이 마법처럼 완료된 프로젝트가 생성됩니다. 파일 확장자도 .js 대신 .tsx를 사용하는 것을 볼 수 있을 겁니다. .tsx는 JSX 문법을 포함하는 TypeScript 파일임을 의미합니다.
TypeScript와 함께 React 컴포넌트를 작성하는 가장 기본적인 방법은 React.FC (Functional Component)를 사용하는 것입니다. Props의 타입을 interface나 type으로 정의하고 컴포넌트에 적용해봅시다.
import React from 'react';
// 1. Props 타입을 interface로 정의합니다.
interface UserProfileProps {
username: string;
email?: string; // '?'는 Optional(선택적) Prop을 의미합니다.
postCount: number;
}
// 2. React.FC를 사용하여 컴포넌트 타입을 지정하고, Generic으로 Props 타입을 전달합니다.
const UserProfile: React.FC<UserProfileProps> = ({ username, email, postCount }) => {
return (
<div className="user-profile">
<h2>{username}</h2>
{email && <p>이메일: {email}</p>} {/* email이 있을 때만 렌더링 */}
<p>작성한 게시글 수: {postCount}</p>
</div>
);
};
export default UserProfile;
이제 다른 컴포넌트에서 UserProfile을 사용할 때, username이나 postCount prop을 전달하지 않거나 잘못된 타입(예: postCount="5")을 전달하면, IDE와 컴파일러가 즉시 오류를 알려줄 것입니다. 정말 든든하죠?
useStateuseState 훅을 사용할 때도 타입을 명시할 수 있습니다. TypeScript는 초기값을 기반으로 타입을 추론하지만, 초기값이 null이거나 여러 타입을 가질 수 있는 경우에는 명시적으로 타입을 지정해주는 것이 좋습니다.
import React, { useState } from 'react';
interface User {
id: number;
name: string;
}
const UserInfo = () => {
// 1. 초기값이 null일 수 있으므로, User 또는 null 타입을 명시합니다.
const [user, setUser] = useState<User | null>(null);
const handleLogin = () => {
setUser({ id: 1, name: 'pixelwave88' });
};
const handleLogout = () => {
setUser(null);
};
if (!user) {
return <button onClick={handleLogin}>로그인</button>;
}
return (
<div>
<p>환영합니다, {user.name}님!</p>
<button onClick={handleLogout}>로그아웃</button>
</div>
);
};
이벤트 객체의 타입도 정확하게 지정하여 안전하게 사용할 수 있습니다. 예를 들어, input 요소의 onChange 이벤트는 React.ChangeEvent<HTMLInputElement> 타입을 가집니다.
import React, { useState } from 'react';
const SearchInput = () => {
const [searchTerm, setSearchTerm] = useState('');
// 이벤트 객체의 타입을 명시합니다.
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.target.value);
};
return (
<input
type="text"
placeholder="검색어를 입력하세요..."
value={searchTerm}
onChange={handleChange}
/>
);
};
이렇게 타입을 지정하면 event.target이 HTMLInputElement라는 것을 TypeScript가 알기 때문에, event.target.value 속성을 안전하게 자동 완성으로 사용할 수 있습니다.
React 프로젝트에 TypeScript를 도입하는 것은 단순히 버그를 줄이는 것을 넘어, 코드의 품질과 개발 경험 자체를 한 단계 끌어올리는 현명한 투자입니다. 처음에는 타입 시스템에 적응하는 시간이 필요하지만, 한번 익숙해지면 TypeScript 없는 React 개발은 상상하기 어려워질 겁니다.
더 명확한 코드, 더 적은 버그, 더 행복한 개발. 오늘부터 여러분의 React 프로젝트에 TypeScript라는 강력한 날개를 달아보는 것은 어떨까요?
로그인 후 댓글을 작성할 수 있습니다.