-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Missing prop validation in React.FunctionComponent #2353
Comments
Technically you typed the variable and not the function; what happens if you use a normal non-arrow function for your component? |
For non-arror function component: function Person(props: PersonProps): React.ReactElement {
return (
<div>{props.username}</div>
)
} there are no errors, but I want to use arrow func with generic type FunctionComponent. For that case, type of props should be inferred from |
That’s something typescript does, but unless the typescript eslint parser passes those types to this plugin, we have no way of leveraging them. It’s a better practice to use non arrows for SFCs anyways, so they have a proper reliable name for debugging. |
Should I create an issue for typescript parser? |
I’m not sure. You could certainly try a PR here to improve the type detection - before filing an issue even on the typescript parser you’d need to have tested and figured out what was needed. The simplest fix, though, is to follow what the most popular styleguide recommends and use normal functions for components. |
I'm having this same error but with functional components. Can't seem to find any good reason why it's happening. I have a functional component. With a typescript props interface. When I access a property off of the prop. I get |
@tx-steven is it an arrow function or a normal function? |
Adding const Person: React.FunctionComponent<PersonProps> = (props: PersonProps): React.ReactElement => (
<div>{props.username}</div>
); |
That’s not redundant; in your case the first one is typing the variable, not the function. |
I guess but I thought TypeScript infers the types — suggesting that it's not required to do both left and right operands. |
It does, this rule is redundant for arrowfunc: React.FC<> case since props are checked by TS |
TypeScript may, but if the eslint typescript parser doesn’t, there’s nothing this plugin can do. |
@skube it works |
@skube A small formality, but the inferred type is more specifically If this isn't an eslint issue would creating an option to ignore this case be worthwhile? |
This is quite annoying, and I don't believe there is any value in using non arrow functions for function components. |
it has lots of value; explicitly that you aren’t relying on name inference, which is unintuitive. |
One advantage of using arrow function is the interface CompProps {
prop1: number
}
const Comp: React.FC<CompProps> = ({ children, prop1 }) => {...} // children inferred from React.FC
function Comp({ children, prop1 }: CompProps) {...} // where to put React.FC? ref: TypeScript#16918 It works in TSLint but not in ESLint. |
Can't you do? : function Comp({ prop1 }: CompProps): React.ReactElement {...} |
Sorry I missed destructuring children in the second component. Added it now. After that, you face the same problem. |
I found this to be an interesting case // fails with prop-types
export const BlockBad: React.FC<BlockProps> = ({ attributeName }) => {
return <div data-attributeName={attributeName} />;
};
// does not fail with prop-types
export const BlockGood: React.FC<BlockProps> = ({ attributeName }) => {
if (attributeName) {
return <div data-attributeName={attributeName} />;
}
}; One workaround is to double-type your components, but it's definitely not behaving consistently as-is export const BlockBad: React.FC<BlockProps> = ({ attributeName }: BlockProps) => { For those seeking ideas about how to type these things. I found both of these resources helpful:
Basically one suggests to use |
@xjamundx very nice. This will work without warnings with the latest versions: import React from 'react'
type CellProps = {
value: string
}
const Cell: React.FunctionComponent<CellProps> = ({ value }: CellProps) => {
return <div className="item">{value}</div>
}
export default Cell |
@leonardorb that will work, but as @xjamundx pointed out, you are typing it twice. It should have been inferred automatically instead. Another potential way of doing it would be: const Cell = ({ value }: CellProps): JSX.Element => {
return <div className="item">{value}</div>
} But not sure what the ideal statement should be. |
Any updates on this? Or at least a best practice, I don't see how typing twice is acceptable in this case... |
I have manually turned off the react/prop-types rule in my config for now. Not sure if there is a better way to handle it. |
Best practice is to just not use arrow functions so I don't think you guys are going to find an easy/simple work around for this if you want to use arrow functions for react components |
I think the rule is pretty useless in the current shape - it's supposed to check if props are typed, not to enforce whether the project should use arrow functions or not. It's not in scope of its responsibility. |
@TeoTN unfortunately by using arrow syntax it seems TS eslint parsers are incapable of attaching the type to an arrow function, so here we are :-/ happy to review a PR that can improve the situation. |
I don't have a solution at hand. If it's unfeasible at the moment, it should be probably removed from the default set of rules. |
My two cents:
|
@rsimp Arrow functions are in no way necessary for any kind of component function, including memo and forwardRef, and arrow functions are WORSE for setting the display name, and the react preset won’t always ensure it’s present. React.memo takes a function as an argument, so variable assignment can’t possibly infer the display name. |
I may have the wrong babel preset listed but here's a quote from gaearon in a react-devtools issue
As for My main point is that tooling can be setup so that a component created with a fat arrow function can have a display name without you explicitly setting it. If someone (and I don't think it's that uncommon) has this kind of project setup, then does it make sense to put an "enforce function components" rule into the recommended ruleset? I don't think it's a bad idea for a rule, but you don't want a rule to be "recommended" if it'll collide with projects on something this arbitrary. All that should matter is that |
@ljharb you're right though, fat arrow is definitely not necessary for It also gets pretty verbose using more than one composition function together. Let's say |
For React, named functions are absolutely enough. If you can find a popular tool that doesn't respect a component's name when available, call it out and i'll send them a PR fixing it. Dan himself says that components shouldn't be arrow functions, because of the name in particular. It is a perfect candidate for being a recommended rule - components should be regular functions. |
I would like to mention another case where I couldn't resolve the linting errors after testing all the proposed solutions in this thread (turning off this lint rule should not be the solution but rather a temporary workaround): import React from 'react';
type MySvgIconProps = React.SVGProps<SVGSVGElement>;
export function MySvgIcon(props: MySvgIconProps) {
const withDefaults = {
...props,
width: props.width ?? 100,
height: props.height ?? 100,
color: props.color ?? '#fff',
};
return (
<svg
xmlns="http://www.w3.org/2000/svg"
enableBackground="new 0 0 24 24"
viewBox="0 0 24 24"
{...withDefaults}>
<rect fill="none" height="24" width="24" />
<path
d="M1,1C20,20,16,-8"
fill={withDefaults.color}
/>
</svg>
);
} Error: 9:18 error 'width' is missing in props validation react/prop-types
10:19 error 'height' is missing in props validation react/prop-types
11:18 error 'color' is missing in props validation react/prop-types Modules:
While typescript understands it fully and doesn't complain, eslint probably doesn't understand |
This rule is just doubling up on the job TS is already doing. Don't recommend. |
@colemars no, it's not, because it can check runtime values, and subsets like integers, and all sorts of things TS is capable of doing. In addition, TS has the flaw that it doesn't properly differentiate the external types of your props, with the internal type of your props, so you can run into situations where your types lie to you. Always use propTypes, especially when using TS. |
I think I'm late here, although if you are using ESlint with TypeScript, be sure to extend |
For now this rule is turned offed. I looked into [this issue](jsx-eslint/eslint-plugin-react#2353). But didn't understand much
why is this thread closed? the way this rule works right now seems obviously redundant if you wanna use arrow functions and React.FC, and no, changing to the other function definitions doesn't look like a good solution, it's just ignoring the problem |
@AdrianDiazG you're not supposed to do that tho - components should be named functions. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as abuse.
This comment was marked as abuse.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
One use case is I expose And on user side, he uses Is it really necessary to ask user do |
I fixed the error
import { useEffect } from 'react';
interface Props {
name: string;
}
const App: React.FC<Props> = ({ name }) => {
useEffect(() => {}, []);
return <div>{name}</div>;
};
export default App; error disappears after importing import React, { useEffect } from 'react';
interface Props {
name: string;
}
const App: React.FC<Props> = ({ name }) => {
useEffect(() => {}, []);
return <div>{name}</div>;
};
export default App; |
Because React.FC doesn’t make sense if React isn’t in scope. |
@ljharb Now that an explicit React import is not required to use JSX, that shouldn't be the case for folks on React 17+ ? Needing to have |
@ericbenedetto16 with that transform - which can be used earlier than react 17, and doesn't have to be used after - React doesn't need to be in scope for jsx syntax, is all. The quality of that experience is irrelevant; it's just how JavaScript works. |
Tell us about your environment
Configuration
What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.
What did you expect to happen?
eslint
show no errors, because type definition actually present in generic typeReact.FunctionComponent<PersonProps>
What actually happened? Please include the actual, raw output from ESLint.
The text was updated successfully, but these errors were encountered: