随着 JavaScript 项目变得越来越复杂,开发者开发了新的工具和语言来提高代码质量和工作流程。
除了单元测试,TypeScript 和 Flow 等静态类型检查器正在成为专业开发团队的标准。无论项目大小,使代码更易于理解并在开发阶段捕获错误的好处已被证明是非常有用的。
在没有使用类型检查工具的情况下处理大型 JavaScript 代码库会让你感到头痛,特别是那些在运行时才会发现的错误会产生很多,但是当你采用了类型检查,或者使用了TypeScript之后,你会发现这些类型的错误大大减少,不仅开发效率得到提高,最重要的是代码的质量得到了极大提升。
在本文中,主要介绍这两个工具,并说明它们的工作方式。并且演示如何将TypeScript 和 Flow 集成到 React 应用程序中。
TypeScript
TypeScript 是微软开发的一种编程语言。它是开源的,并得到了一个庞大而活跃的社区的支持。
TypeScript 是 JavaScript 的类型化超集,可编译为纯 JavaScript。
“类型化”一词表示 TypeScript 要求程序员声明给定变量的数据类型。
“超集”一词表示 TypeScript 允许程序员使用 JavaScript 提供的所有功能,以及一些额外的功能 ,如接口,泛型,装饰器等。
下图展示了 TypeScript 运行方式的高级概述。编译器接收 TypeScript 文件(.ts 或 .tsx),然后将它们“转换”为可由浏览器运行的有效 JavaScript 代码。
我们来看一些用 TypeScript 编写的简单代码:
- function getName(person: IPerson):void{
- console.log(person);
- }
- interface IPerson{
- name: string
- age: number
- }
- getName({"name":"john",age:20});
- getName({age:23}) //Argument of type '{ age: number; }' is not assignable to parameter of type 'IPerson'.
正如我们在上面的代码块中看到的,我们声明了一个函数,该函数接收一个具有两个属性的对象,分别是字符串和数字类型的名称和年龄。调用该函数时,TypeScript 会检查提供的对象的类型是否正确,如果类型不正确,就会像在调用第二个函数的时候代码将无法编译并抛出错误。
Flow
与 TypeScript 相比,Flow 并不是一种编程语言,它被叫做JavaScript 的静态类型检查器,类似于我们经常使用的ESLint,它是由 Facebook开发的。
我们可以通过向常规 JavaScript 文件添加特殊注释来使用 Flow,指示我们期望的类型,或者我们可以让工具推断出期望的类型并在发现任何错误时警告我们。
我们来看看以下 Flow 官方文档的案例:
- // @flow
- function square(n) {
- return n * n; // Error!
- }
- square("2");
注意到上面代码的第一行了吗?为了让工具知道它必须检查哪些文件,我们通过添加注释 @flow在每个要包含在 Flow 监控过程中的文件中。
使用 Flow,您不必更改文件的扩展名,而是继续在带注释的文件.js和.jsx文件中编写普通的 JavaScript。
如果我们保留上面的代码,JavaScript 引擎会因为注释而抛出错误,因此,作为额外的步骤,我们必须在最后编译代码之前删除所有注释。
当然我们可以使用Babel 或者 flow-remove-types等工具来清除它们。
Flow 与 TypeScript 与 React 的集成
一个标准的 React 应用程序
创建 React 应用程序的最简单方法是使用create-react-app工具。
我们将创建两个相同的 React 应用程序,一个用于测试 TypeScript,另一个用于测试 Flow。
首先,让我们通过创建一个没有任何类型检查的 React 应用程序来看看这个工具的实现:
- npx create-react-app demo-app
React启用TypeScript
如果我们从头开始,我们可以像这样使用 –template 标志来创建一个支持 TypeScript 的 React 应用程序:
- npx create-react-app react-ts --template typescript
对于一个新项目这是一个最佳的办法,如果我们想要在现有的项目中启用react的话,我们需要做下面的操作。
- yarn add typescript @types/node @types/react @types/react-dom @types/jest
接下来,我们将现有的.js和.jsx文件重命名为.ts和.tsx。
重启我们的开发服务器之后,你会发现项目目录中多了一个tsconfig.json文件,这个文件是typescript的配置文件,你可以对它进行一些偏好配置。
然后我们创建一个React组件:
- import React from "react";
- interface Props{
- items: Item[]
- }
- export interface Item {
- id:number,
- name:string
- }
- function ItemList(props:Props){
- const listItems = props.items.map(item=>item.name);
- return listItems;
- }
- export default ItemList;
TypeScript 允许我们使用接口声明我们期望的对象类型。
在这里,我们声明了 Props 接口,它有一个属性 item,一个 Item 类型的对象数组——另一个接口有两个属性,一个 number 类型的 id 和一个 string 类型的 name,两者都是必需的。
然后,我们通过添加注解 props:Props 说我们的函数组件 ItemsList 的 props 参数是一个 Props 类型的对象。
让我们ItemsList在我们的App.tsx文件中实现这个组件并声明一个名为 items 的常量,就像一个包含虚拟对象的数组一样,看看 TypeScript 是如何反应的:
您可以看到显示了一个错误,指出 Item 必须包含 id 和 name 属性。如果我们此时尝试运行应用程序,TypeScript 可以避免我们产生错误。
现在让我们删除我们的项目 const 的类型,看看这个错误是否消失:即使我们没有声明项目 const 应该是 type Item[],TypeScript 也足够聪明,可以发现在我们的ItemsList组件中使用它是不安全的。
现在让我们通过向组件添加两个适当的记录来解决这个问题:
- const items: Item[] = [{ id: 1, name: "One" },{ id: 2, name: "Two" }];
我们现在看到应用程序编译并成功执行:通过引入TypeScript,我们避免了运行潜在错误的代码,同时还通过显式声明整个应用程序中使用的类型使代码本身更具可读性。
React启用Flow
- yarn add flow-bin npm run flow init
然后我们创建和之前一样的ItemsList组件。
- import React from 'react';
- function ItemsList(props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;// @flow
- import React from 'react';
- type Item = {
- id: number,
- name: string
- }
- type Props = {
- items: Item[]
- }
- function ItemsList(props: Props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;
运行yarn flow 会出现错误,接下来我们添加一些类型。
- // @flow
- import React from 'react';
- type Item = {
- id: number,
- name: string
- }
- type Props = {
- items: Item[]
- }
- function ItemsList(props: Props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;
重新运行yarn flow,将不会提示任何错误。
每次要使用 Flow 检查文件时,我们都必须运行相同的命令。对于使用 VS Code 的用户,可以使用Flow Language Support在每次保存后自动执行 Flow 检查。其他 IDE 将具有等效功能,只需搜索即可找到与您的环境相关的实现。
TypeScript 与 Flow 的优缺点
TypeScript优点:
- 不仅仅是一个类型检查器: TypeScript向 JavaScript添加了额外的数据结构,如Enums,来自其他语言的开发人员可能缺少这些数据结构。它还具有接口、装饰器和其他使其更加健壮的功能——使开发人员能够编写极其全面的代码。这些功能在大型和企业风格的项目中尤其强大。
- 由 Microsoft 开发: TypeScript 正在接收定期更新并将继续发展。可以肯定地说,在快速发展的 JavaScript 生态系统中,TypeScript 的寿命将比大多数其他“趋势”更长。
- 大型社区:TypeScript 拥有一个庞大而活跃的社区,他们愿意为它的开发做出贡献,并通过回答他们的问题或编写有用的教程来帮助他人。除了官方文档 之外,您还可以找到大量有关 TypeScript 主题的非官方资源。
TypeScript缺点:
- 陡峭的学习曲线:TypeScript 一开始可能是严格且无情的,让开发人员望而却步。它比 Flow 更难和更复杂,因为它更健壮,并且被认为是一种编程语言(或至少是 JavaScript 的“超集”)。TypeScript 也感觉像是一种全有或全无的方法,这会使事情复杂化并减慢具有大量依赖项的大型项目的开发速度。
- 大量重复代码:有人认为 TypeScript 沉淀了大量模板代码,这会增加开发时间并使文件更难理解。在这种情况下,代码极简主义者可能更喜欢轻量级 Flow(或根本不进行类型检查)。
Flow优点:
- 易用性: Flow 比 TypeScript 更宽容,可作为对 JavaScript 中静态类型的更温和的介绍。启动和运行速度更快,而且由于其按文件选择加入的方法,将 Flow 添加到现有项目中也可能更容易。
- 由 Facebook 开发:开发 React 的公司,因此您可以确定这两种工具完全兼容并且可以一起使用。
Flow缺点:
- 更小的社区:Flow 拥有一个更小、更不活跃的社区,这意味着那些试图学习如何使用它并调试可能出现的问题的人可用的资源更少。这也可能意味着它在支持和添加功能方面的未来比 TypeScript 更加不确定。
- 不那么健壮: Flow 可以很好地进行类型检查,但仅此而已。TypeScript 可能更适合具有较长支持范围的更多企业项目,同时考虑到开发人员可以在此类项目中使用其更高级的功能。Flow 可能是更精简项目的更好选择,或者作为将类型检查引入现有项目的一种方式,而不会太痛苦。由您决定哪种工具最适合您的项目和环境。
结论
TypeScript 和 Flow 之间有明显的区别。在功能方面,TypeScript 更健壮,而 Flow 只是一个类型检查器。
尽管 Flow 是由 Facebook创建的,但是对于同公司开发的React框架来说,并没有特别优待之处,毕竟它最初的目的就不是作为react的附属工具,而是作为一个通用项目管理工具。
对于喜欢轻量级,喜欢快速上手的人来说,flow是一个不错的选择,你可以非常快速地入门并使用它。
而如果你在开发一个大型项目,那么typescript应该是你最佳的选择,它庞大的社区让它的发展异常迅速,主流的框架源码都采用了typescript进行开发足以说明问题。