Reputation: 2569
I'm building a React
TreeView
component with Typescript
. I would like the flexibility to be able to inject a template TreeNode
component that renders each node.
How can I type my TreeNode
's props so I can inject TreeNode
into TreeView
as a prop without typescript
complaining that I'm not providing my TreeNode
s props yet, even though they will be down the road when TreeView
builds the hierarchy and feeds each TreeNode
with appropriate props
.
I tried to strip down my code to the minimum:
interface TreeNodeProps {
id: string
title: string
}
const TreeNode: React.SFC<TreeNodeProps > = (props) => {
return (
<div key={props.id}>
<div>{props.title}</div>
<div>{props.children}</div>
</div>
)
}
const TreeView: React.SFC<{treeData: any, TreeNode: JSX.Element}> = (props) => {
// here's the logic where each TreeNode's props will be fed with graph's props.
const buildTreeRecursively = (treeData) =>
treeData.map((node) => {
if (node.children.length > 0) {
return (
<TreeNode id={node.id} title={node.title}>
{buildTreeRecursively(node.children)}
</TreeNode>
)
}
return <TreeNode id={node.id} title={node.title} />
})
return (
<div className={styles.treeView}>
{buildTreeRecursively(props.treeData)}
</div>
)
}
Upvotes: 1
Views: 2250
Reputation: 51816
This seems to work:
const buildTreeRecursively = (treeData: React.PropsWithChildren<TreeNodeProps>[]) =>
treeData.map((node) => {
if (node.children) {
return (
<TreeNode id={node.id} title={node.title}>
{buildTreeRecursively(node.children as React.PropsWithChildren<TreeNodeProps>[])}
</TreeNode>
)
}
return <TreeNode id={node.id} title={node.title} />
})
If I leave the if (node.children.length > 0)
, I get the compile error
Object is possibly 'null' or 'undefined'.
and since the type of node.children
is a superset of React.PropsWithChildren<TreeNodeProps>[]
, we have to cast it since we know we're only using that subset of the type.
I got the idea for treeData
's type by looking at the type hint for props
from
const TreeNode: React.SFC<TreeNodeProps> = (props) => {
return (
<div key={props.id}>
<div>{props.title}</div>
<div>{props.children}</div>
</div>
)
}
which was React.PropsWithChildren<TreeNodeProps>
.
Upvotes: 1