개발은 이슈의 연속이라... 산 하나를 넘으면 또 다른 산이 나를 반겨준다.
TS2739 이슈는 다음과 같은 이슈다.
Type X is missing the following properties from type Y.
"X type에 Y type의 프로퍼티가 존재하지 않습니다."
이슈가 발생한 코드는 다음과 같다.
// BookListItem.tsx
...
type BookListItemProps = {
item: object,
index: number
}
type Item = {
title: string,
image: string,
price: string,
author: string,
pubdate: string
}
const BookListItem = ({ item, index }: BookListItemProps) => {
// TS2739 이슈가 발생한 부분
let { title, image, price, author, pubdate }: Item = item;
title = title.replace(/<b>/gi, "").replace(/<\/b>/gi, "");
return (
...
)
};
export default BookListItem;
// BookList.tsx
...
type BookListProps = {
items: any[];
}
const BookList = ({ items }: BookListProps) => {
if (items.length === 0) {
return <ErrorMessage>검색 결과가 없습니다.</ErrorMessage>;
}
return (
<BookListBlock>
{items.map(
(item: object, i: number) => (
<BookListItem
key={i}
item={item}
index={i}
/>
)
)}
</BookListBlock>
);
};
item 객체에 title, image, price, author, pubdate 프로퍼티가 존재하지 않는다고 하는데, console으로 확인해보면 멀쩡히 존재한다. 아래는 BookListItem이 props로 받는 item 객체이다.
나는 이리저리 구글링을 해보다가 결과가 나오지 않아 심지어는 "BookList가 item을 props로 넘기기 전에 컴파일이 일어나니까 빈 객체를 구조분해하는 연산이 일어나는 건가?" 같은 생각도 했지만, 그건 말이 안 되는 일이다. 연산은 런타임에서 일어나지않는가.
그리고 문제의 원인을 찾아냈다.
위 코드에서 나는 item: object
라고 선언했다. 이것은 item: {}
으로 선언한 것과 같다. 이 객체가 임의의 프로퍼티를 갖게 하려면 item: {title: string, image: string, ...}
와 같이 선언해야 한다.
이건 내가 interface에 대한 개념을 잘 몰라서 일어난 일이다. interface는 어떠한 객체가 이러한 프로퍼티를 갖는다 라는 것을 선언하는 일이다. 내가 코드에서 사용한 type 명령어는 interface와 하는 일은 같으나 세부적으로 차이가 있는 명령어이다.
그래서 다음과 같이 코드를 고치니 잘 작동했다.
// BookListItem.tsx
...
type BookListItemProps = {
item: {
title: string,
image: string,
price: string,
author: string,
pubdate: string
},
index: number
}
const BookListItem = ({ item, index }: BookListItemProps) => {
let { title, image, price, author, pubdate } = item;
title = title.replace(/<b>/gi, "").replace(/<\/b>/gi, "");
return (
...
)
};
export default BookListItem;
// BookList.tsx
...
type BookListProps = {
items: any[];
}
type ItemType = {
title: string,
image: string,
price: string,
author: string,
pubdate: string
}
const BookList = ({ items }: BookListProps) => {
if (items.length === 0) {
return <ErrorMessage>검색 결과가 없습니다.</ErrorMessage>;
}
return (
<BookListBlock>
{items.map(
(item: ItemType, i: number) => (
<BookListItem
key={i}
item={item}
index={i}
/>
)
)}
</BookListBlock>
);
};