I would like to enforce properties on a React component with TypeScript, but I am getting weird behaviour. Bellow I am pasting only simple examples:
function FunctionalComponent(props: { color: string }) {
return <></>;
}
type ComponentWithName<I extends React.FunctionComponent<{ name: string } & React.ComponentProps<I>>> = I;
const component: ComponentWithName<typeof FunctionalComponent> = FunctionalComponent;
The code above will pass even I declared that the component must have a property name. With this code I need to get an errror, because the FunctionalComponent does not include a name property.
On the other hand, this works:
function FunctionalComponent(props: { color: string }) {
return <></>;
}
type ComponentWithName<I extends React.FunctionComponent<{ name: string }>> = I;
const component: ComponentWithName<typeof FunctionalComponent> = FunctionalComponent
This code will throw a TypeScript error, exactly what I need. But the issue is, that the FunctionalComponent can not have additional properties unless I add them manually to the React.FunctionComponent.
The goal is to enforce a component to have the "name" property, but allow to have more additional (not specified) properties.
I am using TypeScript version 4.4.4 and React version 17.0.2
Edit:
The true use case is this:
function Component<
I extends
| React.ComponentClass<
{
onChange: (event: React.ChangeEvent) => void;
} & React.ComponentProps<I>
>
| React.ComponentType<
{
onChange: (event: React.ChangeEvent) => void;
} & React.ComponentProps<I>
>
>(
props: {
component?: I;
} & Omit<React.ComponentProps<I>, "onChange">
) {
const { component: Component, ...rest } = props;
const handleChange = () => {
//
};
return (
<div>
{Component ? (
<Component
{...(rest as React.ComponentProps<I>)}
onChange={handleChange}
/>
) : (
<input onChange={handleChange} />
)}
</div>
);
}
class ComponentClass extends React.Component<{
color: "blue" | "yellow";
}> {
render() {
return (
<input style={{color: this.props.color}} />
);
}
}
function ComponentFunction(props: { color: "blue" | "yellow" }) {
return <input style={{color: props.color}} />;
}
function App() {
return (
<>
<Component component={ComponentClass} color="blue" />
<Component component={ComponentFunction} color="blue" />
</>
);
}
The <Component component={ComponentClass} color="blue" /> will throw an type error but the <Component component={ComponentFunction} color="blue" /> does not. I need to enforce passed components to have the onChange property with the specified type.