[TS] IntrinsicAttributes & (props) is not assignable to type ... 에러
에러 발생
CardSection 컴포넌트로 posts props 를 넘기는 과정에서 발생한 문제.
CardSection 역시 동일한 타입의 props 를 선언했지만 아래와 같은 에러가 발생했다.
MainBlog.tsx (부모 컴포넌트)
posts 변수를 CardSection 컴포넌트의 props 로 전달한다.
해당 변수의 타입은 CardInterface[] 배열이다.
export interface CardInterface {
name: string;
role: string;
}
const MainBlog = () => {
const posts: CardInterface[] = [
{name: 'Post1', role: 'CEO BALENCIAGA'},
{name: 'Post2', role: 'CEO REBORN & YELLOW OCTOPUS'}
];
return (
<section className={styles.teamSection}>
<div className={styles.underlineTitle}>
<p>Posts</p>
</div>
<CardSection posts = {posts}/>
</section>
)
}
export default MainBlog;
CardSection.tsx (자식 컴포넌트)
CardSection 은 posts prop 을 부모로 부터 전달받으며 타입은 CardInterface[] 배열로 선언돼 있다.
부모 컴포넌트에서도 CardInterface[] 타입을 넘겨주기 때문에 왜 에러가 발생하는지 쉽게 이해되지 않았다.
const CardSection = (posts: CardInterface[]) => {
return (
<div className={styles.teamGrid}>
{posts.map((member, index) => (
<div key={member.name}
className={styles.teamMember}
>
<div className={styles.underlineTitle}>
<h3>{member.name}</h3>
</div>
<FlipCard
frontImage={`/team-member-${index + 1}.jpeg`}
altText={member.name}
backContent={
<div>
<h4>{member.name}</h4>
<p>{member.role}</p>
</div>
}
width={400}
height={600}
/>
</div>
))}
</div>
);
}
export default CardSection;
해결
props 를 간단히 구조분해(destructuring) 하여 에러를 해결할 수 있다.
에러의 원인은 하위 컴포넌트로 전달하는 props 의 타입을 지정하지 않았기 때문이다.
엥 분명 CardInterface[] 로 타입을 지정했는데 이게 무슨 말일까?
리액트 컴포넌트에서는 Prop 을 넘길 때 인수 객체 자체가 전달된다.
즉 보내고자 한 prop 이 아래와 같다면,
[
{
"name": "Post1",
"role": "CEO BALENCIAGA"
}
]
function CardSection(posts: CardInterface[])
로 받을 때 posts 의 모습은 아래와 같기 때문이다.
{
"posts": [
{
"name": "Post1",
"role": "CEO BALENCIAGA"
}
]
}
내가 보내고자 한 객체는 이미 posts 를 필드로 한 객체 형태로 넘어오기 때문이다.
이는 리액트 컴포넌트의 props 전달 방식과 관련이 있다.
리액트는 컴포넌트에 단일 props
객체를 전달하기 때문에 이 객체는 부모 컴포넌트에서 전달한 모든 속성을 포함한다.
위 코드의 경우엔 posts 라는 속성을 포함하는 셈이다.
때문에 posts 를 구조분해(destructuring) 하여 컴포넌트 props 에 선언하면 에러를 해결할 수 있다.
변경된 코드
const CardSection = ({posts}: { posts: CardInterface[] }) => {
return (
<div className={styles.teamGrid}>
{posts.map((member, index) => (
<div key={member.name}
className={styles.teamMember}
>
<div className={styles.underlineTitle}>
<h3>{member.name}</h3>
</div>
<FlipCard
frontImage={`/team-member-${index + 1}.jpeg`}
altText={member.name}
backContent={
<div>
<h4>{member.name}</h4>
<p>{member.role}</p>
</div>
}
width={400}
height={600}
/>
</div>
))}
</div>
);
}
export default CardSection;