作者:ConardLi code秘密花园转发链接:https://mp.weixin.qq.com/s/CeFQ23aIiGbXRwY0eBawfg原文链接 https://www.sitepoint.com/react-with-typescript-best-practices/
前言如今, React 和 Typescript 是许多开发人员正在使用的两种很棒的技术。但是把它们结合起来使用就变得很棘手了,有时很难找到正确的答案。不要担心,本文我们来总结一下两者结合使用的最佳实践。
React 和 Typescript 如何一起使用在开始之前,让我们回顾一下 React 和 Typescript 是如何一起工作的。React 是一个 “用于构建用户界面的 Javascript 库” ,而 Typescript 是一个 “可编译为普通 Javascript 的 Javascript类型化超集” 。通过同时使用它们,我们实际上是使用 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 可以与 React 和 webpack 一起使用。幸运的是,官方 Typescript 手册对此提供了配置指南。
希望这能使你轻而易举地了解两者的工作方式。现在,进入最佳时间!
最佳实践我们研究了最常见的问题,并整理了 React with Typescript 最常用的一些写法和配置。这样,通过使用本文作为参考,你可以在项目中遵循最佳实践。
配置配置是开发中最有趣但是最重要的部分之一。我们怎样才能在最短的时间内完成这些配置,从而提供最大的效率和生产力?我们一起来讨论下面的配置
tsconfig.jsonESLint / PrettierVS Code 扩展和配置项目初始化初始化一个 React/Typescript 应用程序的最快方法是 create-react-app 与 Typescript 模板一起使用。你可以运行以下面的命令:
npx create-react-app my-app --template typescript
这可以让你开始使用 Typescript 编写 React 。一些明显的区别是:
.tsx:Typescript JSX 文件扩展tsconfig.json:具有一些默认配置的 Typescript 配置文件react-app-env.d.ts:Typescript 声明文件,可以进行允许引用 SVG 这样的配置tsconfig.json幸运的是,最新的 React/Typescript 会自动生成 tsconfig.json ,并且默认带有一些最基本的配置。我们建议你修改成下面的内容:
{"compilerOptions":{"target":"es5",//指定ECMAscript版本"lib":["dom","dom.iterable","esnext"],//要包含在编译中的依赖库文件列表"allowJs":true,//允许编译Javascript文件"skipLibCheck":true,//跳过所有声明文件的类型检查"esModuleInterop":true,//禁用命名空间引用(import*asfsfrom"fs")启用CJS/AMD/UMD风格引用(importfsfrom"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*"/color :string;children:React.ReactNode;onClick:()=>void;}constButton:React.FC=({children,color='tomato',onClick})=>{returnnstyle={{backgroundColor:color}}onClick={onClick}>{children}}
在此 组件中,我们为 Props 使用 type。每个 Props 双方都有简短的说明,以为其他开发人员提供更多背景信息。 表示 Props 是可选的。children props 是一个 React.ReactNode 表示它还是一个 React 组件。
通常,在 React 和 Typescript 项目中编写 Props 时,请记住以下几点:
始终使用 TSDoc 标记为你的 Props 添加描述性注释 。无论你为组件 Props 使用 type 还是 interfaces ,都应始终使用它们。如果 props 是可选的,请适当处理或使用默认值。Hooks幸运的是,当使用 Hook 时, Typescript 类型推断工作得很好。这意味着你没有什么好担心的。举个例子:
//`value`isinferredasastring//`setValue`isinferredas(newValue:string)=>voidconst[value,setValue]=useState('')
Typescript 推断出 useState 钩子给出的值。这是一个 React 和 Typescript协同工作的成果。
在极少数情况下,你需要使用一个空值初始化 Hook ,可以使用泛型并传递联合以正确键入 Hook 。查看此实例:
typeUser={email:string;id:string;}//thegenericisthe<>//theunionistheUser|null//together,Typescriptknows,"Ah,usercanbeUserornull".const[user,setUser]=useState(null);
下面是一个使用 userReducer 的例子:
typeAppState={};typeAction=|{type:"SET_ONE";payload:string}|{type:"SET_TWO";payload:number};exportfunctionreducer(state:AppState,action:Action):AppState{switch(action.type){case"SET_ONE":return{...state,one:action.payload//`payload`isstring};case"SET_TWO":return{...state,two:action.payload//`payload`isnumber};default:returnstate;}}
可见,Hooks 并没有为 React 和 Typescript 项目增加太多复杂性。
常见用例本节将介绍人们在将 Typescript 与 React 结合使用时一些常见的坑。我们希望通过分享这些知识,您可以避免踩坑,甚至可以与他人分享这些知识。
处理表单事件最常见的情况之一是 onChange 在表单的输入字段上正确键入使用的。这是一个例子:
importReactfrom'react'constMyInput=()=>{const[value,setValue]=React.useState('')//事件类型是“ChangeEvent”//我们将“HTMLInputElement”传递给inputfunctiononChange(e:React.ChangeEvent){setValue(e.target.value)}returnnChange={onChange}id="input-example"/>}
扩展组件的 Props有时,您希望获取为一个组件声明的 Props,并对它们进行扩展,以便在另一个组件上使用它们。但是你可能想要修改一两个属性。还记得我们如何看待两种类型组件 Props、type 或 interfaces 的方法吗 取决于你使用的组件决定了你如何扩展组件 Props 。让我们先看看如何使用 type:
importReactfrom'react';typeButtonProps={color:string;text:string;}typeContainerProps=ButtonProps&{height:number;}constContainer:React.FC=({color,height,width,text})=>{return{text}}
如果你使用 interface 来声明 props,那么我们可以使用关键字 extends 从本质上“扩展”该接口,但要进行一些修改:
importReactfrom'react';interfaceButtonProps{color:string;text:string;}interfaceContainerPropsextendsButtonProps{height:number;}constContainer:React.FC=({color,height,width,text})=>{return{text}}
两种方法都可以解决问题。由您决定使用哪个。就个人而言,扩展 interface 更具可读性,但最终取决于你和你的团队。
第三方库无论是用于诸如 Apollo 之类的 GraphQL 客户端还是用于诸如 React Testing Library 之类的测试,我们经常会在 React 和 Typescript 项目中使用第三方库。发生这种情况时,你要做的第一件事就是查看这个库是否有一个带有 Typescript 类型定义 @types 包。你可以通过运行:
#yarnyarn add @types/#npmnpm install @types/
例如,如果您使用的是 Jest ,则可以通过运行以下命令来实现:
#yarnyarn add @types/jest#npmnpm install @types/jest
这样,每当在项目中使用 Jest 时,就可以增加类型安全性。
该 @types 命名空间被保留用于包类型定义。它们位于一个名为DefinitelyTyped 的存储库中,该存储库由 Typescript 团队和社区共同维护。
总结由于信息量大,以最佳方式一起使用 React 和 Typescript 需要一些学习时间,但是从长远来看,其收益是巨大的。在本文中,我们介绍了配置,组件,Props,Hook,常见用例和第三方库。尽管我们可以更深入地研究各个领域,但这应涵盖帮助您遵循最佳实践所需的 80% 。
如果您希望看到它的实际效果,可以在GitHub上看到这个示例。
推荐Typescript知识点文章https://github.com/jsjoeio/react-ts-example
了不起的 Typescript 入门教程「实践篇」
了不起的 Typescript 入门教程「基础篇」
Typescript 常见问题整理(60多个)「上」
Typescript 常见问题整理(60多个)「下」
深入Typescript难点梳理讲解
Vue3.0之前你必须知道的Typescript实战技巧
深入Typescript难点梳理讲解
Vue3.0之前你必须知道的Typescript实战技巧
你需要的 React + Typescript 50 条规范和经验
Typescript详细概括【思维导图】
Vue3.0 尝鲜 Hook Typescript 取代 Vuex【项目实践】
Typescript详细概括【思维导图】
「新消息」基于Javascript/Typescript 编程环境Deno1.0 即将发布
「干货」一张页面引起的项目架构思考(rax+Typescript+hooks)
深入浅出Vue3 跟着尤雨溪学 Typescript 之 Ref 【实践】作者:ConardLi code秘密花园转发链接:https://mp.weixin.qq.com/s/CeFQ23aIiGbXRwY0eBawfg原文链接 https://www.sitepoint.com/react-with-typescript-best-practices/