I want to create a component handling multiple HTML element with the same properties/logic.
import React from 'react';
import styled from 'styled-components';
interface GridProps {
htmlElement: 'div' | 'main' | 'header',
}
const GridFactory = (props: GridProps) => {
switch (props.htmlElement) {
case 'header':
return styled.header``;
case 'main':
return styled.main``;
case 'div': default :
return styled.div``;
}
}
export const Test = () => (
<GridFactory htmlElement='div'>
<p>content...</p>
</GridFactory>
)
It fails with that error :
Type '{ children: Element; htmlElement: "div"; }' is not assignable to type 'IntrinsicAttributes & GridProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & GridProps'.
Add an explicit children prop to GridProps :
interface GridProps {
htmlElement: 'div' | 'main' | 'header',
children?: React.ReactNode | React.ReactNode[];
}
It gives the corresponding error :
'GridFactory' cannot be used as a JSX component.
Its return type 'StyledComponent<"header", DefaultTheme, {}, never> | StyledComponent<"div", DefaultTheme, {}, never>' is not a valid JSX element.
Type 'StyledComponent<"header", DefaultTheme, {}, never>' is not assignable to type 'Element | null'.
Type 'String & StyledComponentBase<"header", DefaultTheme, {}, never> & NonReactStatics<never, {}>' is missing the following properties from type 'Element': type, props, key
How can I achieve it ?
Since your styled.head returns component type rather than React.Element so you can improve your stuff as below:
Specify returned type of your component as stateless functional component React.SFC, you also benefit from this by no need to specify children prop cause it's a part of the type SFC:
const GridFactory: React.SFC<GridProps> = (props) => { ...
Then assign styled component as functional component as well such as Header:
const Header: React.SFC = styled.header``;
To sum up, the full code would be:
interface GridProps {
htmlElement: 'div' | 'main' | 'header',
}
const Header: React.SFC = styled.header``;
const GridFactory: React.SFC<GridProps> = (props) => {
switch (props.htmlElement) {
case 'header':
return <Header />;
// More to come
default: return null
}
}
The error says that you cannot pass the prop "children" to your component because it doesn't provide that type on the prop interface declaration. In fact, your GridProps interface doesn't declare such property. children is the prop that you "set" when you pass a child component to a parent component, like in your example
export const Test = () => (
<GridFactory htmlElement='div'>
<p>content...</p> //This is passed as the children prop of your GridFactory
</GridFactory>
)
To make typescript stop complaining about it, you should change your interface declaration to
interface GridProps {
htmlElement: 'div' | 'main' | 'header';
children: React.Node | React.Node[];
}
Now your Prop type allows you to pass a children prop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With