Next.js
React 컴포넌트에서 타입 단언이 자꾸 늘어날 때
Props 타입을 제대로 정의해서 타입 단언의 악순환을 벗어나는 방법.
React 프로젝트가 커지면서 자꾸만 as 타입 단언이 늘어난다. 처음에는 한두 개 정도로 시작했지만, 어느 순간 코드 곳곳에 as any나 as unknown이 널려있다면 뭔가 잘못된 신호다.
타입 단언이 늘어나는 이유
대부분 Props 타입이 제대로 정의되지 않았기 때문이다.
// ❌ 나쁜 예
function UserCard({ user }: any) {
return <div>{user.name}</div>; // user가 any라서 그냥 쓸 수 있음
}
// 나중에 이걸 쓸 때
<UserCard user={someValue as User} /> // 타입 단언 필요
최근 React와 TypeScript의 변화
React 18.2부터 React.FC를 안 쓰는 게 권장되고 있다. Props를 명확하게 정의해야 한다.
// ✅ 좋은 예
interface UserCardProps {
user: User;
onClick?: (id: string) => void;
}
function UserCard({ user, onClick }: UserCardProps) {
return (
<div onClick={() => onClick?.(user.id)}>
{user.name}
</div>
);
}
부모에서 Props를 정의할 때
interface ParentProps {
users: User[];
onSelect?: (user: User) => void;
}
function Parent({ users, onSelect }: ParentProps) {
return (
<div>
{users.map(user => (
<UserCard
key={user.id}
user={user} // ✅ 타입 단언 없음
onClick={onSelect}
/>
))}
</div>
);
}
모바일 화면에서 특히 주의할 점
반응형 디자인에서 Props가 조건부로 전달될 때가 있다.
interface ResponsiveProps {
isMobile: boolean;
content: string;
action?: (id: string) => void; // 필수가 아님을 명시
}
function Responsive({ isMobile, content, action }: ResponsiveProps) {
return isMobile ? (
<MobileView content={content} /> // action 생략 가능
) : (
<DesktopView content={content} action={action} />
);
}
이벤트 핸들러는 더 신경써야 한다
// ❌ 위험한 패턴
function Form() {
const handleChange = (e: any) => {
// e를 어떻게 써야 할지 모름
};
}
// ✅ 안전한 패턴
function Form() {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.currentTarget.value; // 명확함
};
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
// 마찬가지로 명확
};
return (
<>
<input onChange={handleChange} />
<button onClick={handleClick}>Submit</button>
</>
);
}
빌드 타임에 확인하기
npm run build
타입 에러가 있으면 빌드 실패하도록 설정해두고, 타입 단언이 필요한 경우는 주석으로 이유를 남겨라.
// @ts-expect-error: API 응답이 항상 이 구조를 보장하지 않음
const data = response.data as ApiResponse;
언제 타입 단언은 괜찮은가?
- 외부 라이브러리 타입이 불완전할 때
- API 응답을 파싱한 직후
- DOM 쿼리 결과 (querySelector의 반환값)
이런 경우들은 단언이 실제로 필요하고 정당하다. 하지만 컴포넌트 내부에서 Props로 인한 단언은 Props 타입을 제대로 정의해서 없애야 한다.
결국 "이 Props는 정확히 뭔가?"를 명확히 하는 게 문제 해결의 시작이다.