I am working on creation of reusable front components in React using Typescript and I am struggling with a feature which seems to be possible in classic packages.
I would like to be able to nest children of a certain type in "container components" and retrieve each sets of children in the main component.
I tried a lot of variants in the type of children props such as:
export type DataGridChild = typeof DataGridColumns | typeof DataGridActions;
export type DataGridProps<T> = BaseProps & {
data: T[];
children: React.ReactElement<DataGridChild> | React.ReactElement<DataGridChild>[];
}
But then I can't find a way to retrieve each child with the right type. Also TypeScript does not throw any error if I add a DataGridColumn container component twice for instance.
In the end I would like to have a component usable with this kind of code:
<DataGrid data={persons}>
<DataGridColumns>
<DataGridColumn field="name" />
<DataGridColumn field="age" />
<DataGridColumn field="weight" />
<DataGridColumn field="birthDate" type="date" />
</DataGridColumns>
<DataGridActions>
<DataGridAction text="Action 1" onClick={(rd) => console.log("Action 1 clicked")} />
</DataGridActions>
</DataGrid>
I can't find anything on the web. Does anybody has an idea on how to make it?
Thanks a lot :)
Since you are using Union
s, you will ultimately do that which the so called classic packages do: Union
narrowing. See more at Working with Union
Types. [typescriptlang.org]
Let’s break down the code. You declared a type alias called DataGridChild
for the Union
:
typeof DataGridColumns | typeof DataGridActions
So that anywhere a DataGridChild
is used, a typeof DataGridColumns
or a typeof DataGridActions
is expected. Since that’s the choice, expect to perform narrowing.
Next you declared a type alias DataGridProps<T>
for the anonymous type built by extending a type BaseProps
and including two properties:
BaseProps & {
data: T[];
children: React.ReactElement<DataGridChild> | React.ReactElement<DataGridChild>[];
}
T
.Union
type whose value may be any one of:React.ReactElement<DataGridChild>
Or an Array
of:React.ReactElement<DataGridChild>
Again since that’s the choice, expect to perform narrowing too.With the explanations now out of the way, you should be able to answer your questions.
For posterity however, let’s answer them together.
I can't find a way to retrieve each child with the right type.
Perform Union
narrowing.
Also TypeScript does not throw any error if I add a
DataGridColumn
container component twice for instance.
You only defined a type alias DataGridProps<T>
which I suspect you used to declare and define the prop of element DataGrid
.
If you didn’t define a prop Interface
for neither DataGridColumns
nor DataGridActions
, then their props are implicitly any
. Because of this, TypeScript will not provide type checking hence no type checking errors. Define an Interface
for the components to provide finer control and type safety for the components.