挣扎于 TypeScript、React、Eslint 和简单的箭头函数组件

Posted

技术标签:

【中文标题】挣扎于 TypeScript、React、Eslint 和简单的箭头函数组件【英文标题】:Struggling with TypeScript, React, Eslint and simple Arrow Functions components 【发布时间】:2021-12-23 22:11:59 【问题描述】:

我整个上午都在为这个问题苦苦挣扎,但在任何地方都找不到解决方案。我是打字稿的新手,我正在尝试使用 Eslint 和 Prettier 正确设置它,以确保代码格式正确。

所以,我在创建功能组件时面临的问题。根据备忘单,我正在尝试导出一个简单的组件,例如:

import React from "react";

type DivProps = 
  text: string;
;

const Div = ( text : DivProps): JSX.Element => (<div>text</div>)

export default Div;

但是,eslint 在抱怨,说“函数组件不是函数表达式”。

运行修复时,它会将我的函数转换为未命名的函数:

const Div = function ( text : DivProps): JSX.Element 
  return <div>text</div>;
;

然后它会抱怨说“意外的未命名函数”。

即使我尝试将函数重构为:

function Div( text : DivProps): JSX.Element 
  return <div>text</div>;
;

我仍然收到同样的错误,说“函数组件不是函数表达式”。

我的 .eslintrc.js 文件是:

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: ,
    ,
  ,
;

感谢您对此的任何帮助!

PS:如果您在 eslintrc 文件中看到任何其他需要修改/改进的内容,请告诉我。正如我所提到的,我是 TypeScript 的新手,所以我仍在尝试找出 linting 的最佳选择。

干杯!

亚历杭德罗

【问题讨论】:

函数组件有没有尝试使用FC类型? const Div:FC&lt;Props&gt;=(props)=&gt;null。你可以直接从'react'导入FC 您好,感谢您的建议。不幸的是,它没有用。它一直在抱怨函数组件不是函数表达式。 尝试自动修复命令 - npm run lint -- --fix 嗨,感谢您的评论,但解决方案实际上是根据我在下面的回复更改 eslintrc 文件。出于某种原因,在我的情况下,默认行为是更喜欢函数表达式,而根据文档,它应该是函数声明。无论如何,在 eslintrc 文件中指定一个选项解决了这个问题。 【参考方案1】:

更新:这实际上是a bug in the airbnb configuration。

正确的设置应该是function-declaration,因此正确的解决方案是覆盖.eslintrc.js中的规则

"react/function-component-definition": [
  2,
  
    namedComponents: "function-declaration",
  ,
],

^ 目前airbnb设置里默认有an open PR to make that patch,所以这个改动会让你的项目和预期的设置一致。

注意:您可能需要考虑导航到 relevant issue 并对其进行投票,以便维护人员知道您正在处理它。

另一种选择:降级 airbnb 规则

another answer 提到:如果您愿意,也可以将您的 airbnb 规则版本降级到引入“坏”规则之前(v18.2.1 是没有此规则的最新版本)。这是通过更新你的 package.json 来完成的:

"devDependencies": 
  ...
  "eslint-config-airbnb": "^18.2.1"

请注意,这意味着您的项目不会使用最新的 airbnb 样式指南,因此您可能会决定最好直接覆盖该规则。


我之前的回答,会根据 linter 创建“有效”代码:

我也遇到过这个问题;我能够弄清楚如何编写符合 airbnb 规则的代码,但是......我发现结果很尴尬,我不确定为什么它会是首选结果。

在默认规则下,您需要 (A) 使用函数表达式定义组件,而且 (B) 不能使用匿名函数(这是为了防止堆栈跟踪中出现“匿名函数”),等等还必须命名函数:

const MyComponent = function MyComponent()  ... 

所以用你的例子:

const Div = function Div( text : DivProps): JSX.Element 
  return <div>text</div>;
;

这满足了 linter 但是......哎呀,我说的对吗?

【讨论】:

太棒了,谢谢你的回答!你是对的,在 eslintrc 文件中指示函数声明以符合 Airbnb 样式规则更有意义。干杯! @AlejandroAburto 很高兴这很有帮助!如果您认为它有力地回答了问题,请考虑将其标记为答案! 哇,好新鲜,谢谢,希望他们尽快修复【参考方案2】:

好的,所以我不知道这是否是正确的答案,但最后更改 Eslint 中的设置帮助我更改了组件的函数类型。我在 .eslintrc.js 文件中添加了以下规则:

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

这样,eslint 将只接受组件的箭头函数,而不是函数表达式(默认情况下)。

【讨论】:

当你找到答案时,请告诉我们!但它的工作! tks! @LuanLuanLuan 找到了答案(如果你没有看这个问题)——这最终是 airbnb linting 规则中的一个错误。我在下面对这个问题的回答中有更多详细信息。【参考方案3】:

在 package.json 中编辑以下依赖项对我有用

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

感谢@https://***.com/a/70051760/9558119 的更新答案,我被困在这里好几天了

【讨论】:

我认为这应该被认为是正确的答案。除非他们在提到的公关请求中修复它。 18.1 是旧版本的配置——在引入错误规则之前——当然欢迎人们降级,但如果目标是在新项目中使用最新设置,那么我d 建议使用 19 并手动修复此错误,直到补丁上线。

以上是关于挣扎于 TypeScript、React、Eslint 和简单的箭头函数组件的主要内容,如果未能解决你的问题,请参考以下文章

在基于 TypeScript/eslint/Webpack 的构建环境中检测未使用的导出符号

React with TypeScript 系列 --概述

React - 使用 TypeScript vs Flow vs?

如何在 React 应用程序的 typescript 文件中导入 js 模块(使用绝对路径)?

使用带有 TypeScript 的 React Native 找不到变量 Symbol

简单用 React+Redux+TypeScript 实现一个 TodoApp