I am trying make Reuse-able style-components cards. I used typescript for my React app. I made children type children?: string | JSX.Element
. But in my card container it got undefined and give typescript error: Types of property 'children' are incompatible.
even though I made children optional
. I Really don't get what is main error and how to fix it.
I share my code in code-sandbox.
**Ps: It does not thorw errors in codesandbox**
This is my card component
import React from "react";
import styled from "styled-components";
export interface ICardProps {
title?: string;
secondaryText?: string;
hoverable?: boolean;
thumbnailUrl?: string;
coverImage?: string;
url?: string;
children?: string | JSX.Element;
}
const Container = styled.div<ICardProps>`
box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2),
0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px;
border-radius: 6px;
background: white;
margin-bottom: 20px;
&:hover {
${({ hoverable }) =>
hoverable
? `box-shadow: 0 0 20px rgba(0, 0, 0, 0.05), 0 0px 60px rgba(0, 0, 0, 0.08)`
: null}
}
`;
const Title = styled.h1`
margin: 0;
font-size: 24px;
`;
const SecondaryText = styled.p`
margin: 0;
color: #6b6b6b;
`;
const Thumbnail = styled.div<ICardProps>`
width: 70px;
height: 70px;
border-radius: 50%;
background-image: url(${({ url }) => url});
background-size: cover;
margin-right: 10px;
`;
const TitleBar = styled.div`
display: flex;
align-items: center;
`;
const CoverImage = styled.img`
width: 100%;
border-radius: 6px 6px 0 0;
`;
const Content = styled.div`
padding: 20px;
`;
const ChildrenContent = styled.div`
background: pink;
`;
const Card = ({
title,
secondaryText,
thumbnailUrl,
coverImage,
children,
hoverable,
...props
}: ICardProps) => {
return (
<Container
{...props}
{...{ hoverable, title, secondaryText, thumbnailUrl, coverImage, ...props }}>
{coverImage ? <CoverImage src={coverImage} /> : null}
<Content>
<TitleBar>
{thumbnailUrl ? <Thumbnail url={thumbnailUrl} /> : null}
<div>
{title ? <Title>{title}</Title> : null}
{secondaryText ? <SecondaryText>{secondaryText}</SecondaryText> : null}
</div>
</TitleBar>
{typeof children === `string` ?
<ChildrenContent> {children}</ChildrenContent> :
children
}
</Content>
</Container>
)
};
export default Card;
This is how I am trying to use it
import React from "react";
import styled from "styled-components/macro";
import { Card } from "./lib/Card";
const ThinnerCard = styled(Card)`
width: 400px;
`;
export default function App() {
return (
<div>
<ThinnerCard
coverImage="http://www.fillmurray.com/500/300"
thumbnailUrl="http://www.fillmurray.com/100/100"
title="This is the title"
secondaryText="Secondary title"
/>
<Card title="Only a title" secondaryText="And a second text" />
<Card>
<h1> Hello I'm a "children" props</h1>
</Card>
</div>
);
}
I found a solution. I extends my typescript props like extendsReact.HTMLAttributes<HTMLDivElement>
.
export interface ICardProps extends React.HTMLAttributes<HTMLDivElement> {
title?: string;
secondaryText?: string;
hoverable?: boolean;
thumbnailUrl?: string;
coverImage?: string;
url?: string;
style?: React.CSSProperties;
}
const Card = ({
title,
secondaryText,
thumbnailUrl,
coverImage,
hoverable,
children,
...props
}: ICardProps) => {
return (
<Container
{...props}
{...{
hoverable,
title,
secondaryText,
thumbnailUrl,
coverImage,
...props
}}
>
{coverImage ? <CoverImage src={coverImage} /> : null}
<Content>
<TitleBar>
{thumbnailUrl ? <Thumbnail url={thumbnailUrl} /> : null}
<div>
{title ? <Title>{title}</Title> : null}
{secondaryText ? (
<SecondaryText>{secondaryText}</SecondaryText>
) : null}
</div>
</TitleBar>
</Content>
{ children ? (
<ChildrenContent> {children}</ChildrenContent>
) :
children
}
</Container>
);
};