eslint-plugin-react: Add "destructureInSignature: never" to destructuring-assignment
That would forbid to use
const MyComponent = ({ name }: {name: string}) => <h1>Hello, { name } </h1>
Reason:
- in TS, it looks less readable
- forces our developers to use only one variant
- seeing
propsin code (e.g., in review) helps identify react components with 100% sure
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 6
- Comments: 23 (10 by maintainers)
I completely understand your concern. Mutating the props object can indeed lead to unwanted behavior and introduce bugs in an application.
However, I’d like to mention that the
no-param-reassignESLint rule was specifically created to prevent parameter mutation. You can leverage the props option of this rule to ensure that any attempt to mutate a parameter will be caught and prevented, like this:Additionally, when you’re destructuring your params inside the signature, it can be a bit challenging to assign default values. In such cases, it’s much easier to do so when performing the destructuring outside, like this:
Another advantage of destructuring outside the signature is that you cannot mark the props ‘as const’ when doing it inside, which helps prevent accidental reassignments:
In the end, both approaches have their pros and cons, and it’s essential to choose the one that best suits your specific use case. This is why I believe it’s valuable to support and allow both approaches within the ESLint rules, as they cater to different coding styles and scenarios.
When it’s purely style, yes! However, never destructuring in the signature actually makes your code worse and less robust, which will cause bugs in your code - so it’s not purely a matter of style, and it would be reckless for me to enable that.
If WebStorm doesn’t work well with an idiomatic style, WebStorm is broken, not the style - file a bug with them.
Obviously if you want to access the props object then it’s fine to move it to the body, but passing props objects to children wholesale is an antipattern.
Nope, that’s the thing. My extensive experience tells me that this is indeed an actual bug, and at times a catastrophic one, since mutating props invalidates any predictions about React rendering.
Hey @ljharb! 👋🏻
I’ve thoroughly read the entire thread once again to make sure I didn’t miss any points
From what I gathered, it seems there’s a concern that some people might accidentally mutate the props object without fully understanding its implications. While this is a valid concern, I believe it’s more of a potential misunderstanding rather than an actual bug.
Is there any other potential “bug” that you think I might have missed?
It’s so untrue…
@ljharb Just to be clear about the spread in the function signature won’t protect you from bugs.
What a spread operator does? It deep copies the data if it is not nested. For nested data, it deeply copies the topmost data and shallow copies of the nested data. Destructuring in the signature just protects me from reference the original props object but allows me to reference nested data of props object. This is only a partial protection in case there is a nested data in the props.
It is entirely the responsibility of the developer to protect props from mutations. You may still need to be careful when modifying nested objects or arrays to avoid unintentionally modifying the original object.
While it’s true that using the spread operator and destructuring can help protect your code from unintended mutations, not using destructuring in the function signature does not necessarily make your code worse or less robust.
In conclusion, while using the spread operator and destructuring in the function signature can provide some benefits, it’s up to the developer to choose their preferred coding style and ensure they are handling data carefully to prevent unintended mutations.
Destructuring in the signature has concrete benefits, whether using TS or not - it avoids the props object being accessible at all, which avoids a huge class of bugs caused by mutating or exposing that mutable props object.
This isn’t a mere aesthetic difference, and I don’t think it would be a good idea to have a rule that encouraged it.
@RomainLanz have you read the entire thread? not having it in the signature can cause bugs, so it’s not purely a style choice.
So what is the status of this issue? Why is it closed?
It seems fair to ask for a
neveroption for thedestructureInSignature. Why would we be able to force the destructuring in the signature but not force the destructuring to not be in the signature?Please reconsider this issue as it seems to be a nice-to-have feature and should not break anything.
Sorry, guys. I really don’t like destructuring in signature too.
My reasons:
WebStorm doesn’t work good with indentation when cutting and pasting props for reordering in construction like this;
destructuring in signature sucks for a few parameters occupying multiple lines while I prefer it to be more compact like this (depends on max line length):
sometimes I want to access
props.in IDE in order to watch which properties are also available for me as well as passing partial or the wholepropsto children components easily.Nobody uses
props.x, because we’re using restructuring on the next lineThere is
We have components with 10-20 props and putting them in a function definition is less readable for me.
Looks like basically, you’re saying “we don’t use it - nobody needs it”, which is untrue.
I don’t think it’s less readable in TS; and usually the props types are defined outside the component in a type/interface.
@max-prtsr nope, just the one that makes decisions here. an eslint rule is supposed to be opinionated - choices are for style, but any choice that causes bugs is indeed one that folks should be actively prevented from making.
@ljharb you’re basically selling your opinion as the only valid.
The bugs I’m concerned about are exclusively about mutating the props object, since that’s the one React looks at when rerendering.
I prefer to destructure it in the first line of function body, it doesn’t make my code worse and less robust obviously. There is prefer-destructuring rule allowing to avoid not destructured properties.
And what if I want to combine
propswith some other variables using spread operator and pass the result to child component? It’s very useful when child component has common properties with its parent (wrapper component).The notice about multiline destructuring in signature is still actual.
That should suggest to you that “having 10-20 props” is what causes the readability problem, not “where they’re destructured”.
Either way, I think this:
is pretty objectively more readable than this:
especially with long lists, because it duplicates the
propsreference, and the longer the list, the farther apart they are.What I’m saying is that not all stylistic preferences are equal, and sometimes, a choice actively harms the maintainability of a codebase, and in these cases, it’s better for an eslint plugin (which by definition are meant to be opinionated) not to tacitly endorse the pattern by providing configuration for it.
You are welcome to modify the rule in your own plugin, and use that.
Maybe, but an option of using props and destructuring in the function body would be nice for me 😃