I have been struggling all morning with this issue and couldn't find the solution anywhere. I am new to typescript, and I am trying to set it up properly with Eslint and Prettier to ensure the code is properly formated.
So, the issue I am facing when creating functional components. As per the cheatsheet, I am trying to export a simple component such as:
import React from "react";
type DivProps = {
text: string;
};
const Div = ({ text }: DivProps): JSX.Element => (<div>{text}</div>)
export default Div;
However, eslint is complaining, saying that "Function component is not a function expression".
When running fix, it will convert my function to an unnamed function:
const Div = function ({ text }: DivProps): JSX.Element {
return <div>{text}</div>;
};
And then it will complain saying "Unexpected unnamed function.".
Even if I try to refactor the function to:
function Div({ text }: DivProps): JSX.Element {
return <div>{text}</div>;
};
I still get the same error saying that "Function component is not a function expression".
My .eslintrc.js file is:
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ["airbnb", "plugin:@typescript-eslint/recommended", "prettier"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["@typescript-eslint", "react-hooks", "prettier"],
rules: {
"react-hooks/rules-of-hooks": "error",
"prettier/prettier": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": ["error"],
"react/jsx-filename-extension": [
1,
{
extensions: [".tsx"],
},
],
"import/prefer-default-export": "off",
"import/extensions": [
"error",
"ignorePackages",
{
ts: "never",
tsx: "never",
},
],
},
settings: {
"import/resolver": {
typescript: {},
},
},
};
Appreciate any help on this!
PS: If you see any other thing you would amend/improve in the eslintrc file let me know. As I mentioned, I am new to TypeScript so I am still trying to find out the best options for linting.
Cheers!
Alejandro
FINAL Update: This has been corrected as of eslint-config-airbnb
version 19.0.4
The best thing to do would be to update your copy of that package to 19.0.4 or above.
Past Update: this is actually this was a bug in the airbnb configuration versions 18.2.1 to 19.0.2
The correct setting should be function-declaration
, and so the correct solution is to override the rule in your .eslintrc.js
"react/function-component-definition": [
2,
{
namedComponents: "function-declaration",
},
],
^ There is currently was an open PR a now merged PR to make that patch in the airbnb settings by default, so this change will make your project consistent with the intended settings.
Note: You may want to consider navigating to the relevant issue and upvoting it so the maintainers know you're dealing with it.
Now that this has been resolved you should update your version to 19.0.4 or above.
Another Option: Downgrading airbnb rules
As mentioned by another answer: if you prefer, you can also downgrade your version of the airbnb rules to before the "bad" rule was introduced (v18.2.1 is the latest version without this rule). This is done by updating your package.json:
"devDependencies": {
...
"eslint-config-airbnb": "^18.2.1"
}
Note that this means your project won't be using the latest airbnb styleguide, so you might decide that it's preferable to simply override the rule.
My previous answer, which will create "valid" code according to the linter:
I faced this issue as well; I was able to figure out how to write code that adheres to the airbnb rules, but... I find the result pretty awkward, and I'm not really sure why it would be the preferred outcome.
Under the default rules you need to both (A) define your component using a function expression, but also (B) you can't use anonymous functions (this is to prevent "anonymous function" in stack traces), and so have to also name the function:
const MyComponent = function MyComponent() { ... }
So using your example:
const Div = function Div({ text }: DivProps): JSX.Element {
return <div>{text}</div>;
};
This satisfies the linter but... Yikes, am I right?