eslint-plugin-react
eslint-plugin-react copied to clipboard
[Bug]: False positive for react/no-unused-prop-types and passthrough
Is there an existing issue for this?
- [x] I have searched the existing issues and my issue is unique
- [x] My issue appears in the command-line and not only in the text editor
Description Overview
The following code causes a false positive on react/no-unused-prop-types:
export type TestProp = {
name: string;
};
const Component1: FC<TestProp> = ({ name }) => {
return <div>{name}</div>;
};
const Component2: FC<{ Component: FC<TestProp>; props: TestProp }> = ({ Component, props }) => {
return <Component name={props.name} />;
};
const Component3: FC<TestProp> = (props: TestProp) => {
return <Component2 Component={Component1} props={props} />;
};
Error: 'name' PropType is defined but prop is never used.
The error goes away when commenting out Component3.
Expected Behavior
The code above should be accepted by the linter.
eslint-plugin-react version
v7.37.4
eslint version
v8.57.1
node version
v20.15.0
This is a very strange pattern - why pass a component and a props object around instead of just passing an element directly?
Either way, you’re meant to access all of the props individually in each component in which it’s defined, so if you want to write your code this way, then you may need go use an override comment in Component3.
I didn't include the whole complexity here to keep this example minimal. In the use case, Component2 is rather complex and generates additional properties that are fed into Component1. Now we have ~10 components that can be used for Component1, and each of these should receive an abstraction in the form of Component3.
I would be happy to suppress this warning via // eslint-disable-next-line at Component3, but that does not fix the issue since the problem is raised in line 2 at name: string;. I can only suppress the warning for the whole file or line by line in the type definition. In either case, I lose the ability to check whether all properties are used in Component2 (which works just fine when Component3 is disabled).
Unfortunately the minimal example doesn't really justify or explain the (uncommon and bizarre) approach - can you provide something a bit more thorough so I can understand why this is a reasonable way to architect your components?
Here are some additional details on the setup. I cannot show any of the real code, though, since it belongs to a client.
- The client uses a popular frontend table library.
- This frontend library is extended by a custom UI for the filters.
- There are different types of custom filters with different arguments.
- They share a lot of setup code (e.g. to make them "float").
Roughly speaking, the code looks like this (I am skipping some of the typing here):
type InnerFilterProps = {
name: string;
computedProperty: /* ... */
};
const CustomFilter: FC<{ Component: FC<InnerFilterProps>; innerProps: InnerFilterProps }> = ({ Component, innerProps, ...customFilterProps }) => {
// complex setup
return (
<outerComponents>
<Component name={props.name} computedProperty={somethingComputedInTheSetup} />
</outerComponents>;
)
};
Now, there are filters declared like
const InnerFilterString: FC<InnerFilterProps & StringFilterProps> = (/*...*/) => { /* ... */ };
const CustomFilterString: FC<InnerFilterProps & StringFilterProps> = (props) => {
return <CustomFilter Component={InnerFilterString} props = {props}/>
}
const InnerFilterInteger = /* ... */
// ... more of those
Finally, the call in the table library looks roughly like
const columns = [
{
// ...
filter: {
Component: CustomFilterString,
customProps: { /* ... */ }
}
}
]
<LibraryTable columns={columns}/>
The complexity has multiple reasons:
- We have no control over the interface of the library where we insert our custom component.
- The setup code in
CustomFilteris rather complex and we do not want to duplicate it multiple times. - Some of the parameters to the inner filter are computed in the
CustomFilter. - There are also some generics involved which I skipped over here, making it infeasible to disassemble and reassemble the properties in all places.
I'll leave the help wanted label on this, in case someone can figure this out, but I don't see enough info to change my intuition that the code architecture is what needs fixing here.