eslint-plugin-react-use-propswithchildren
v1.0.0
Published
Require components that use children to type their props via PropsWithChildren<Props>, and disallow declaring children explicitly inside Props
Maintainers
Readme
eslint-plugin-react-use-propswithchildren
An ESLint plugin that requires functional React components that use children to type their
props via React's own PropsWithChildren<Props> generic, and disallows declaring children
explicitly as a field inside Props (whether or not PropsWithChildren is also used).
Rules
react-use-propswithchildren/require-props-with-children
Flags a functional component (arrow function, function expression, or function declaration) that returns JSX and takes a single props parameter, in three directions:
- The component uses
children(destructured, or accessed viaprops.children) but its props type isn'tPropsWithChildren<Props>/React.PropsWithChildren<Props>→ flagged as missingPropsWithChildren. - The props type declares
childrenexplicitly as its own field (e.g.type Props = { children: ReactNode; title: string }) → always flagged, even when the type is also wrapped inPropsWithChildren<...>—childrenshould come fromPropsWithChildrenalone. - The props type is
PropsWithChildren<Props>but the component never useschildrenat all → flagged as unnecessary.
Incorrect
type Props = { title: string; children: React.ReactNode };
const Card = ({ title, children }: Props) => {
return (
<div>
<h1>{title}</h1>
{children}
</div>
);
};
const Panel = ({ title }: PropsWithChildren<{ title: string }>) => {
return <h1>{title}</h1>;
};Correct
type Props = { title: string };
const Card = ({ title, children }: PropsWithChildren<Props>) => {
return (
<div>
<h1>{title}</h1>
{children}
</div>
);
};
const Panel = ({ title, children }: PropsWithChildren<{ title: string }>) => {
return (
<div>
<h1>{title}</h1>
{children}
</div>
);
};Installation
npm install eslint-plugin-react-use-propswithchildren --save-devUsage
Flat config (eslint.config.js, ESLint 9+)
import reactUsePropsWithChildren from "eslint-plugin-react-use-propswithchildren";
export default [...reactUsePropsWithChildren.configs["flat/recommended"]];Or wire the rule up manually:
import reactUsePropsWithChildren from "eslint-plugin-react-use-propswithchildren";
export default [
{
plugins: { "react-use-propswithchildren": reactUsePropsWithChildren },
rules: {
"react-use-propswithchildren/require-props-with-children": "error",
},
},
];Legacy config (.eslintrc)
{
"plugins": ["react-use-propswithchildren"],
"extends": ["plugin:react-use-propswithchildren/recommended"]
}Or wire the rule up manually:
{
"plugins": ["react-use-propswithchildren"],
"rules": {
"react-use-propswithchildren/require-props-with-children": "error"
}
}Compatibility
Requires ESLint 8 or later. ESLint 9's flat config is supported via
configs['flat/recommended']. Type-aware detection works when your ESLint config parses
TypeScript files with @typescript-eslint/parser (a dependencies entry of this package, so it's
installed automatically).
Limitations
require-props-with-children reads the destructured parameter's real TS type annotation. A named
type reference (Props, PropsWithChildren<Props>) is resolved against a same-file
interface/type declaration by name; a type imported from elsewhere can't be resolved from a
single file's AST, so the "explicit children in Props" check simply doesn't fire for it (there's
nothing local to inspect).
When there's no type annotation at all (plain JS/JSX), the "explicit children in Props" and
"unnecessary PropsWithChildren" checks can't fire (there's no type to inspect), but "missing
PropsWithChildren" still fires whenever children is used — untyped code has no PropsWithChildren
to check against in the first place.
children usage is detected as either a destructured { children } property, or a
props.children member access when the parameter isn't destructured. A children prop forwarded
under another local name ({ children: kids }) is still recognized, since detection keys off the
destructured property's name, not its local binding.
Testing
npm testRuns the rule through ESLint's RuleTester (test/*.test.js) via Node's built-in test runner.
