React and ESLint are both common JavaScript-based technologies used across the modern web. React is the framework developed by Meta that makes building reactive web applications simpler. ESLint is a pluggable static analysis tool (linter) for JavaScript and JSX code. Together, they are quite powerful. However, it takes some extra consideration to ensure they work well together.
Introduction: The Issue
One issue that arises when working with React and ESLint is that the common destructed syntax for functional React components confuses ESLint. As with typical JavaScript code, ESLint expects function parameters to be atomic inputs. However, destructuring a React props parameter essentially creates a more complex argument that ESLint isn’t able to natively understand. Consider the following example:
/** * A sample component that uses destructuring of the props component. * * @param {string} prop1 - A prop that's a string. * @param {string} prop2 - A prop that's a string. * @param {string} prop3 - A prop that's a string. */ function SampleComponent({ prop1, prop2, prop3 }) {}
Here we see a functional react component that destructures the props element into its constituent elements. For each of these constituent prop parameters, there is an entry in the docstring describing them — as is common syntax for JS-based functions. However, the destructuring causes ESLint to see the parameters as a single Object such that the @param
entries are interpreted as not matching the params in the function signature. Without customizing your ESLint package, you’re likely to see the following warning:
ESLint: @param "prop1" does not match an existing function parameter. (jsdoc/check-param-names)
The first approach to addressing this concern would be to customize the ESLint package to suit the needs of the project. Let’s say updating the .eslintrc
file is beyond your reach and you need to address this issue directly. Essentially, there are two approaches here: adding an @param
entry for the props object and dot-denoting the rest or not using the destructuring syntax in the function signature. Let’s consider what each approach would look like.
Option 1: Add @param Entry for Props
ESLint is tripping up here because it’s unable to recognize the individual components of the destructured props. However, adding awareness of an implicit props object that has been destructured will help satisfy ESLint. This can be done as follows:
/** * A sample component that uses destructuring of the props component. * * @param {Object} props - The props object. // <--- new @param here * @param {string} props.prop1 - A prop that's a string. // <--- dot notation here * @param {string} props.prop2 - A prop that's a string. // <--- dot notation here * @param {string} props.prop3 - A prop that's a string. // <--- dot notation here */ function SampleComponent({ prop1, prop2, prop3 }) {}
Here we see the addition of the @param {Object} props
to the docstring. With this, we can indicate via dot-notation access that the listed params are being accessed via that object as props.prop1
. This approach has the benefit of not modifying the signature and not requiring changing any syntax within the function where the props are used.
Option 2: Avoid Signature Destructuring
Another approach to avoid ESLint griping about the params being destructured is to not destructure them in the first place. The destructuring syntax is commonplace in JS-based code however and makes variable access syntactically lighter. One approach to maintain this efficiency and keep ESLint happy is to destructure the props inside the function rather than in the function signature as such:
/** * A sample component that uses destructuring of the props component. * * @param {Object} props - The Props object. */ function SampleComponent(props) { const { prop1, prop2, prop3 } = props; //<--- the destructuring }
Here we see the docstring being simplified greatly and the destructuring taking place on the first line within the function. This solves the ESLint concern at the expense of making the function docstring less insightful and the signature much more generic.
Final Thoughts
ESLint is a powerful static code analysis tool that is industry standard for React, TypeScript, and vanilla JavaScript projects. Major companies like AirBNB even have custom ESLint packages to match their workflow configurations. There’s always a trade-off when customizing linters between handling things globally vs. handling them locally.
Global concerns are easily controlled via files like .eslintrc
but sometimes gloss over concerns that should be getting addressed on the local file and/or function level. For example, disabling warnings about missing @param
entries would remove the warnings related to the issue discussed here. However, it would essentially disable a major use-case for linters in the process: ensuring proper documentation of function parameters.
There is no one-size-fits-all solution here. Only your project and available resources will help make a confident decision on how best to address such concerns. Also keep in mind that linters, while powerful, don’t have to be perfectly configured on day one or address every concern of coding standards or quality.