47

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

Alejandro Aburto
  • 1,232
  • 1
  • 6
  • 11
  • Did you try to use `FC` type for function components? `const Div:FC=(props)=>null`. You can import `FC` from 'react' directly – captain-yossarian from Ukraine Nov 11 '21 at 12:17
  • Hi, thanks for your suggestion. Unfortunately it didn't work. It keeps complaining it that a function component is not a function expression. – Alejandro Aburto Nov 11 '21 at 14:00
  • Try auto fix command - npm run lint -- --fix – Sarang Kakkoth Nov 20 '21 at 12:30
  • Hi, hanks for your comment, but the solution was actually to change the eslintrc file as per my response below. For some reason, the default behaviour, in my case, was to prefer function expressions, while as per the documentation it should have been function declarations. Anyways, specifying an option in the eslintrc file solved the issue. – Alejandro Aburto Nov 20 '21 at 21:14

5 Answers5

57

Ok, so I don't know if it is the correct answer, but finally changing the settings in Eslint helped me to change the type of function for Components. I added the following rule to my .eslintrc.js file:

"react/function-component-definition": [
  2,
  {
    namedComponents: "arrow-function",
    unnamedComponents: "arrow-function",
  },
],

With this, eslint will ONLY accept arrow functions for Components, rather than function expressions (as default).

Alejandro Aburto
  • 1,232
  • 1
  • 6
  • 11
  • When you find the answer, tell to us please! but it's worked! tks! – LuanLuanLuan Nov 19 '21 at 20:03
  • 3
    @LuanLuanLuan found an answer (in case you aren't watching this question) -- it's ultimately a bug in the airbnb linting rules. More detail in my answer to this question below. – slifty Nov 21 '21 at 04:26
  • @slifty what about this package `eslint-config-airbnb-typescript-prettier` –  Feb 23 '22 at 14:58
  • @chuklore you'll want to open an issue with that package's maintainers asking them to update the setting if it is still using the old; in the mean time you can follow the other alternate suggestions in the various answers to this issue. – slifty Feb 23 '22 at 17:38
  • This works for me. I think this is conflicting with the `plugin:react/recommended`? – NeoZoom.lua Mar 25 '22 at 03:47
  • How can I turn off this rule? I want to use `function-declaration` or `arrow-function` both are acceptable. – Nam Lee Jun 27 '22 at 02:05
  • Hi @NamLêQuý, you have 2 options. you can use an array to indicate both options, like `namedComponents: ["arrow-function", "function-declaration]`, or you can turn off this rule by using `"react/function-component-definition": [0]`. Hope this helps. – Alejandro Aburto Jun 27 '22 at 11:32
47

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?

slifty
  • 13,062
  • 13
  • 71
  • 109
  • 1
    Awesome, thanks for your answer! And you are right, it makes more sense to indicate function declaration in the eslintrc file to be consistent with Airbnb styling rules. Cheers! – Alejandro Aburto Nov 21 '21 at 18:19
  • @AlejandroAburto Glad this was helpful! If you think it robustly answered the question please consider marking it as the answer! – slifty Dec 06 '21 at 21:42
  • This did not work for me but Alejandro Aburto's did – Ian Dec 25 '21 at 19:47
  • @Ian it all depends on your lint settings and the targeted guide of your project. these settings *do* work, but of course if you use them then you can't define your react components with arrow functions (you will need to use function declarations) – slifty Dec 26 '21 at 04:03
  • 5
    i have eslint-config-airbnb version 19.0.4 and this error – romanown Mar 02 '22 at 21:39
  • 1
    @romanown it's possible you're facing another issue; note that if your code can still violate the linting rules and would need to be corrected! The issue OP made was that the linting rules contradicted one another. That should no longer be the case. – slifty Mar 02 '22 at 22:21
  • thank You. i added exclude rules and all work. – romanown Mar 04 '22 at 22:06
  • How can I turn off this rule? I want to use `function-declaration` or `arrow-function` both are acceptable. – Nam Lee Jun 27 '22 at 02:02
  • @NamLêQuý This might be helpful -- https://stackoverflow.com/questions/37002574/eslint-turning-off-a-specific-rule-across-a-project – slifty Jun 27 '22 at 13:06
6

It fixes my issue, so you can try this one

'react/function-component-definition': [
  2,
  {
    namedComponents: ['arrow-function', 'function-declaration'],
    unnamedComponents: 'arrow-function',
  },
],
Bablu Ahmed
  • 4,412
  • 5
  • 49
  • 64
3

I've found the solution to overcome the issue. Based on the answer from @slifty. In case you want to support both "arrow-function" & "function-declaration", set the value to an array of strings. Consider my setup as below

"react/function-component-definition": [
  "error",
  {
    "namedComponents": ["function-declaration", "arrow-function"],
    "unnamedComponents": "arrow-function"
  }
]

This solution working with "eslint-config-airbnb": "^19.0.4

Cuong Nguyen
  • 407
  • 4
  • 7
2

Editing following dependencies in package.json worked for me

"devDependencies": {
"eslint-config-airbnb": "^18.1.0"}

Thanks for the updated answer @ https://stackoverflow.com/a/70051760/9558119 , I was stuck here for days

Sarang Kakkoth
  • 381
  • 3
  • 9
  • 1
    I Think this should be considered to be the right answer. unless they fix it in the mentioned pr request. –  Dec 11 '21 at 02:06
  • 2
    18.1 is an older version of the config -- before the bad rule was introduced -- folks are welcome to downgrade of course BUT if the goal is to use the latest settings in a new project then I'd recommend using 19 and fixing this mistake manually until the patch is live. – slifty Dec 11 '21 at 02:45