Reputation: 27952
I'm trying to convert my React app (create-react-app) to use Typescript and I've hit a hurdle with a component that uses render props.
Here's a simplified version which still has the error...
import React from 'react'
type Props = {
fullWidth?: boolean,
renderRightSection?: React.ReactNode
}
const Component = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
let {fullWidth, renderRightSection, ...inputProps} = props
return (
<InputWrapper fullWidth={props.fullWidth}>
<input {...inputProps} ref={ref} />
{renderRightSection && renderRightSection()}
</InputWrapper>
)
})
The error is with the renderRightSection() bit and looks like this:
let renderRightSection: string | number | true | {} | React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | ... | (new (props: any) => React.Component<any, any, any>)> | null) | (new (props: any) => React.Component<...>)> | React.ReactNodeArray | React.ReactPortal
This expression is not callable.
No constituent of type 'string | number | true | {} | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<...>)> | ReactNodeArray | ReactPortal' is callable.ts(2349)
Any help would really be appreciated.
Edit:
To show how I am using the component in a form:
<Textbox
name="username"
type="text"
fullWidth={true}
placeholder="Choose a Username"
renderRightSection={() => (
<TextboxBadge>
{usernameAvailable && <span>Available</span>}
{!usernameAvailable && <span>Taken</span>}
</TextboxBadge>
)}
/>
Edit:
And here's what it's used for, rendering a block of JSX on the right hand side of the textbox.
Upvotes: 8
Views: 19306
Reputation: 517
I used the accepted answer, and it worked, but I didn't like it. I was able to get this working by typing the component being passed in as ReactNode
and then calling it like this:
interface MyComponentProps {
detailComponent: ReactNode;
}
const MyComponent = ({ detailComponent }: MyComponentProps) => {
return <div>{detailComponent}</div>;
};
export default MyComponent;
This is what it looks like when called from the parent:
const myComponent = <OfficeDetail />;
return <MyComponent detailComponent={myComponent} />;
Upvotes: 0
Reputation: 27952
I solved the problem. It seems that when creating the type for the component the render prop needs to be a function which returns JSX. I had no idea that you could do this:
type Props = {
fullWidth?: boolean,
className?: string,
renderRightSection?: () => JSX.Element
}
But it worked!
Upvotes: 14