
React로 UI 컴포넌트를 개발하다 보면, 실제로는 데이터 전체가 아닌 일부 필드만 필요한 경우가 자주 발생한다. 예를 들어 API에서 받아온 데이터는 수십 개의 필드를 가지고 있지만, 특정 컴포넌트에서는 그중 3~4개만 사용하는 경우다. 이럴 때 우리는 어떤 방식으로 타입을 다루는 게 가장 합리적일까?
이번 글에서는 Partial, Pick, 그리고 타입 단언을 어떻게 활용하면 되는지 실전 예제를 바탕으로 정리한다.
다음은 ItemData라는 데이터 구조이다. 실제 서비스에서는 이 구조가 매우 크고 복잡할 수 있다.
참고로 모든 코드는 실제 프로젝트 코드가 아닌 대체용어로 변경하였다 혹시 모르니까~~
export interface ItemData {
id: string
type: string
category: string
label: string
detail: string
score: string
note: string
createdAt: string
updatedAt: string
isActive: boolean
tags: string[]
}
그리고 아래와 같은 컴포넌트가 있다고 하자
interface SimpleItemCardProps {
itemData: ItemData
onClickDetail: (e: React.MouseEvent<HTMLElement>) => void
className?: string
}
export const SimpleItemCard: React.FC<SimpleItemCardProps> = ({ itemData }) => {
const { category, label, score, note } = itemData
return (
<div>
<div>{category}</div>
<div>{label}</div>
<div>{score}</div>
<div>{note}</div>
</div>
)
}
문제는 이 컴포넌트를 테스트하거나 미리보기를 만들고 싶을 때 발생한다.
전체 데이터를 만들 필요 없이, 아래처럼 일부 필드만 포함한 객체를 넘기고싶은데 ItemData의 type, detail, createdAt, isActive, tags 등은 SimpleItemCard컴포넌트에서 필요가 없지만 필수속성이기 때문에 일부 필드만 포함한 객체를 넘기는 방법은 없을까?라는 고민을 하였다.
참고로 위와같은 형태로 사용하게되면 다음과 같은 에러를 발생시킨다..
TS2740: Type '{ category: string; label: string; score: string; note: string; }' is missing the following properties from type 'ItemData': id, type, detail, createdAt, updatedAt, and more.
Partial<ItemData> 사용Partial<T>란?Partial<T>는 TypeScript의 유틸리티 타입 중 하나로, 기존 타입의 모든 속성을 선택적(optional)으로 만든다.
즉 컴포넌트에 전체 데이터가 필요하지 않고, 일부만 넘기고 싶을 때 임시로 사용할 수 있기에 현재 나의 상황에 적합하다고 판단!
Partial를 사용하면 다음과 같이 작성할 수 있다
interface SimpleItemCardProps {
itemData: Partial<ItemData> // 변경된 부분
// ...
}
Partial<T>사용 시 주의할 점undefined 체크가 필요하다.Partial<T>는 모든 필드가 optional이 되기 때문에, 컴포넌트 내부에서 필드 접근 시 undefined체크가 필요할 수 있다.Pick, Omit, 전체 타입 등)을 사용하는 것이 유지보수에 유리하다.Pick<ItemData, '필드명들'> 사용특정 필드만 명시적으로 사용하고 싶다면 Pick을 사용하는 것이 더 안전하다. 이 방법은 불필요한 필드를 포함하지 않고 명확한 타입만 전달하고 싶을 때 유용하다.
type SimpleItemData = Pick<ItemData, 'category' | 'label' | 'score' | 'note'>
interface SimpleItemCardProps {
itemData: SimpleItemData
// ...
}
더미 데이터는 이렇게 작성할 수 있다
const itemData: SimpleItemData = {
category: '전자기기',
label: '블루투스 이어폰',
score: '4.5',
note: '신제품 할인 중',
}
이 방식은 타입 안정성을 유지하면서도 가벼운 컴포넌트 렌더링이 가능하다.
테스트나 개발 중 급하게 넘겨야 할 경우, 타입 오류를 무시하고 강제로 캐스팅하는 방법도 있다.
const itemData = {
category: '전자기기',
label: '블루투스 이어폰',
score: '4.5',
note: '신제품 할인 중',
} as unknown as ItemData
하지만 이 방법은 타입 안전성을 완전히 무시하므로, 절대로 운영 코드에서는 사용하지 않아야 한다.
| 상황 | 추천 방법 |
|---|---|
| 임시 테스트 / 빠른 UI 확인 | Partial<ItemData> |
| 일부 필드만 명확히 지정하고 싶은 경우 | Pick<ItemData, '필드들'> |
| 전체 필드가 필요하고 타입을 지켜야 하는 경우 | ItemData 전체를 채운 mock 객체 생성 |
| 타입 검사를 무시하고 싶은 경우 (비추천) | as unknown as ItemData |
React + TypeScript 환경에서는 타입을 명확히 지정하고 필요한 필드만 뽑아서 사용하는 것이 유지보수성과 안정성에 큰 도움이 된다. Partial, Pick, Omit과 같은 유틸리티 타입을 잘 활용하면, 더 유연하고 재사용성 높은 컴포넌트를 만들 수 있다.
특히 API 데이터 구조가 방대해질수록, 각 컴포넌트가 정확히 어떤 데이터만 사용하는지 명확히 구분하는 것이 중요하다. 테스트, 스토리북 작성, 혹은 더미 UI 구성 시에도 이번 전략은 매우 실용적으로 활용해볼 수 있을것같음!!
이번 작업을 통해서 타입스크립트 유틸리티에 대해서도 다시금 다뤄봐야겠다는 생각!!
const itemData: SimpleItemData = {
category: '애완동물',
label: '기니피그',
score: '100',
note: '폭풍다이어트중',
}