用TypeScript编写React的最佳实践

前端桃园

共 9753字,需浏览 20分钟

 ·

2020-06-11 23:23



本文译自 https://www.sitepoint.com/react-with-typescript-best-practices/

2a4f73eb2713df4dc8175d1ead29fbe6.webp

如今, ReactTypeScript 是许多开发人员正在使用的两种很棒的技术。但是把他们结合起来使用就变得很棘手了,有时很难找到正确的答案。不要担心,本文我们来总结一下两者结合使用的最佳实践。

React 和 TypeScript 如何一起使用

在开始之前,让我们回顾一下 ReactTypeScript 是如何一起工作的。React 是一个 “用于构建用户界面的 JavaScript 库” ,而 TypeScript 是一个 “可编译为普通 JavaScriptJavaScript类型化超集” 。通过同时使用它们,我们实际上是使用 JavaScript 的类型化版本来构建 UI。

将它们一起使用的原因是为了获得静态类型化语言( TypeScript )对 UI 的好处:减少 JS 带来的 bug,让前端开发更安全。

TypeScript 会编译我的 React 代码吗?

一个经常被提到的常见问题是 TypeScript 是否编译你的 React 代码。TypeScript 的工作原理类似于下面的方式:

  • TS:“嘿,这是你所有的UI代码吗?”
  • React:“是的!”
  • TS:“酷!我将对其进行编译,并确保你没有错过任何内容。”
  • React:“听起来对我很好!”

因此,答案是肯定的!但是稍后,当我们介绍 tsconfig.json 配置时,大多数时候你都想使用 "noEmit": true 。这是因为通常情况下,我们只是利用 TypeScript 进行类型检查。

概括地说, TypeScript 编译你的 React 代码以对你的代码进行类型检查。在大多数情况下,它不会发出任何 JavaScript 输出。输出仍然类似于非 TypeScript React 项目。

TypeScript 可以与 React 和 Webpack 一起使用吗?

是的, TypeScript 可以与 Reactwebpack 一起使用。幸运的是,官方 TypeScript 手册对此提供了配置指南。

希望这能使你轻而易举地了解两者的工作方式。现在,进入最佳实践!

最佳实践

我们研究了最常见的问题,并整理了 React with TypeScript 最常用的一些写法和配置。这样,通过使用本文作为参考,你可以在项目中遵循最佳实践。

配置

配置是开发中最无趣但是最重要的部分之一。我们怎样才能在最短的时间内完成这些配置,从而提供最大的效率和生产力?我们一起来讨论下面的配置

  • tsconfig.json
  • ESLint / Prettier
  • VS Code 扩展和配置

项目初始化

初始化一个 React/TypeScript 应用程序的最快方法是 create-react-appTypeScript 模板一起使用。你可以运行以下面的命令:

npx create-react-app my-app --template typescript

这可以让你开始使用 TypeScript 编写 React 。一些明显的区别是:

  • .tsxTypeScript JSX 文件扩展
  • tsconfig.json:具有一些默认配置的 TypeScript 配置文件
  • react-app-env.d.tsTypeScript 声明文件,可以进行允许引用 SVG 这样的配置

tsconfig.json

幸运的是,最新的 React/TypeScript 会自动生成 tsconfig.json ,并且默认带有一些最基本的配置。我们建议你修改成下面的内容:

{
  "compilerOptions": {
    "target""es5", // 指定 ECMAScript 版本
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ], // 要包含在编译中的依赖库文件列表
    "allowJs"true, // 允许编译 JavaScript 文件
    "skipLibCheck"true, // 跳过所有声明文件的类型检查
    "esModuleInterop"true, // 禁用命名空间引用 (import * as fs from "fs") 启用 CJS/AMD/UMD 风格引用 (import fs from "fs")
    "allowSyntheticDefaultImports"true, // 允许从没有默认导出的模块进行默认导入
    "strict"true, // 启用所有严格类型检查选项
    "forceConsistentCasingInFileNames"true, // 不允许对同一个文件使用不一致格式的引用
    "module""esnext", // 指定模块代码生成
    "moduleResolution""node", // 使用 Node.js 风格解析模块
    "resolveJsonModule"true, // 允许使用 .json 扩展名导入的模块
    "noEmit"true, // 不输出(意思是不编译代码,只执行类型检查)
    "jsx""react", // 在.tsx文件中支持JSX
    "sourceMap"true, // 生成相应的.map文件
    "declaration"true, // 生成相应的.d.ts文件
    "noUnusedLocals"true, // 报告未使用的本地变量的错误
    "noUnusedParameters"true, // 报告未使用参数的错误
    "experimentalDecorators"true, // 启用对ES装饰器的实验性支持
    "incremental"true, // 通过从以前的编译中读取/写入信息到磁盘上的文件来启用增量编译
    "noFallthroughCasesInSwitch"true 
  },
  "include": [
    "src/**/*" // *** TypeScript文件应该进行类型检查 ***
  ],
  "exclude": ["node_modules""build"] // *** 不进行类型检查的文件 ***
}

其他建议来自 react-typescript-cheatsheet 社区

ESLint / Prettier

为了确保你的代码遵循项目或团队的规则,并且样式保持一致,建议你设置 ESLintPrettier 。为了让它们配合的很好,请按照以下步骤进行设置。

1.安装依赖

yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react --dev

2.在根目录下创建一个eslintrc.js 文件并添加以下内容:

module.exports =  {
  parser:  '@typescript-eslint/parser',  // 指定ESLint解析器
  extends:  [
    'plugin:react/recommended',  // 使用来自 @eslint-plugin-react 的推荐规则
    'plugin:@typescript-eslint/recommended',  // 使用来自@typescript-eslint/eslint-plugin的推荐规则
  ],
  parserOptions:  {
  ecmaVersion:  2018,  // 允许解析最新的 ECMAScript 特性
  sourceType:  'module',  // 允许使用 import
  ecmaFeatures:  {
    jsx:  true,  // 允许对JSX进行解析
  },
  },
  rules:  {
    // 自定义规则
    // e.g. "@typescript-eslint/explicit-function-return-type": "off",
  },
  settings:  {
    react:  {
      version:  'detect',  // 告诉 eslint-plugin-react 自动检测 React 的版本
    },
  },
};

3.添加 Prettier 依赖

yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev

4.在根目录下创建一个 .prettierrc.js 文件并添加以下内容:

module.exports =  {
  semi:  true,
  trailingComma:  'all',
  singleQuote:  true,
  printWidth:  120,
  tabWidth:  4,
};
  1. 更新 .eslintrc.js 文件:
module.exports =  {
  parser:  '@typescript-eslint/parser',  // 指定ESLint解析器
  extends:  [
    'plugin:react/recommended',  // 使用来自 @eslint-plugin-react 的推荐规则
    'plugin:@typescript-eslint/recommended',  // 使用来自@typescript-eslint/eslint-plugin的推荐规则
    'prettier/@typescript-eslint',  // 使用 ESLint -config-prettier 禁用来自@typescript-eslint/ ESLint 与 prettier 冲突的 ESLint 规则
    'plugin:prettier/recommended',  
  ],
  parserOptions:  {
  ecmaVersion:  2018,  // 允许解析最新的 ECMAScript 特性
  sourceType:  'module',  // 允许使用 import
  ecmaFeatures:  {
    jsx:  true,  // 允许对JSX进行解析
  },
  },
  rules:  {
    // 自定义规则
    // e.g. "@typescript-eslint/explicit-function-return-type": "off",
  },
  settings:  {
    react:  {
      version:  'detect',  // 告诉 eslint-plugin-react 自动检测 React 的版本
    },
  },
};

VSCode 扩展和设置

我们添加了 ESLintPrettier ,下一步就是在保存时自动修复/美化我们的代码。

首先,安装 VSCode 的 ESLint extensionPrettier extension 。这将使 ESLint 与您的编辑器无缝集成。

接下来,通过将以下内容添加到您的中来更新工作区设置 .vscode/settings.json

{
    "editor.formatOnSave"true
}

保存时, VS Code 会发挥它的魔力并修复您的代码。很棒!

组件

React 的核心概念之一是组件。在这里,我们将引用 React v16.8 以后的标准组件,这意味着使用 Hook 而不是类的组件。

通常,一个基本的组件有很多需要关注的地方。让我们看一个例子:

import React from 'react'

// 函数声明式写法
function Heading(): React.ReactNode {
  return <h1>My Website Headingh1>
}

// 函数扩展式写法
const OtherHeading: React.FC = () => <h1>My Website Headingh1>

注意这里的关键区别。在第一个例子中,我们使用函数声明式写法,我们注明了这个函数返回值是 React.ReactNode 类型。相反,第二个例子使用了一个函数表达式。因为第二个实例返回一个函数,而不是一个值或表达式,所以我们我们注明了这个函数返回值是 React.FC 类型。

记住这两种方式可能会让人混淆。这主要取决于设计选择。无论您选择在项目中使用哪个,都要始终如一地使用它。

Props

我们将介绍的下一个核心概念是 Props。你可以使用 interfacetype 来定义 Props 。让我们看另一个例子:

import React from 'react'

interface Props {
  name: string;
  color: string;
}

type OtherProps = {
  name: string;
  color: string;
}

// Notice here we're using the function declaration with the interface Props
function Heading({ name, color }: Props): React.ReactNode {
  return <h1>My Website Headingh1>
}

// Notice here we're using the function expression with the type OtherProps
const OtherHeading: React.FC = ({ name, color }) =>
  <h1>My Website Headingh1>

关于 interfacetype ,我们建议遵循 react-typescript-cheatsheet 社区提出的准则:

  • 在编写库或第三方环境类型定义时,始终将 interface 用于公共 API 的定义。
  • 考虑为你的 React 组件的 StateProps 使用 type ,因为它更受约束。”

让我们再看一个示例:

import React from 'react'

type Props = {
   /** color to use for the background */
  color?: string;
   /** standard children prop: accepts any valid React Node */
  children: React.ReactNode;
   /** callback function passed to the onClick handler*/
  onClick: ()  => void;
}

const Button: React.FC = ({ children, color = 'tomato', onClick }) => {
   return <button style={{ backgroundColor: color }} onClick={onClick}>{children}button>
}

在此

浏览 56
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报