I have a case where I want to explicitly scope the child component of a React.FC to be of a specific type, overriding the default which is: React.ReactNode.
The purpose is that I'm creating a little library, and I want to have compile-time errors which will tell the user that he can only use a specific component type as a child for the parent.
An OK example would be:
<MainComponent>
<ChildComponent>
</MainComponent>
An FAILED example would be:
<MainComponent>
<Route ...>
<ChildComponent>
</MainComponent>
ChildComponent
and fails the check.Default children property in React.FC
is derived from:
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
type PropsWithChildren<P> = P & { children?: ReactNode };
What I have tried is something like this:
Omit<React.FC, 'children'> & {
children: ChildComponent | ChildComponent[];
}
However I can either get only React.ReactNode
or an union of my children and React.ReactNode
.
I can't seem to figure out how to overwrite the prop to only explicitly use my type for this prop.
I'm using Typescript 3.5.3 and Omit
/ Extend
... that now became the part of standard TS library.
No this is not possible.
<MainComponent>
<ChildComponent/>
</MainComponent>
is JSX syntax and will get compiled to
React.createElement(MainComponent, null, React.createElement(ChildComponent, null));
And then we have to look at how typescript handles these JSX elements. This is clearly documented in their handbook:
The JSX result type
By default the result of a JSX expression is typed as any. You can customize the type by specifying the JSX.Element interface. However, it is not possible to retrieve type information about the element, attributes or children of the JSX from this interface. It is a black box.
You can override children
to only be string
or function
(to realize something like the render prop pattern) but any custom component will get casted to JSX.Element
and this is a blackbox as stated in the documentation.
There is currently an issue open for this, in which a roadmap how JSX.Element
can be generalized to support your use case, but without any clear timeline when and to which extent or if it will land.
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