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
}
}