diff --git a/docs/learn-react-ts3/01.md b/docs/learn-react-ts3/01.md index 21f77cc..45d642a 100644 --- a/docs/learn-react-ts3/01.md +++ b/docs/learn-react-ts3/01.md @@ -892,7 +892,7 @@ const orderDetail: OrderDetail = { 因此,类型别名似乎与接口非常相似。类型别名和接口之间有什么区别?主要区别在于类型别名不能像使用接口那样从扩展或实现。因此,对于不需要继承的简单结构,我们应该使用接口还是使用类型别名?没有强有力的理由选择这两种方法。然而,无论我们选择哪种方法来提高代码的可读性,我们都应该保持一致。 -# 班级 +# 类 类在许多编程语言中都具有功能,包括 JavaScript。它们让我们以类似于接口和类型别名的方式使用类型注释来塑造对象。但是,类比接口和类型别名有更多的特性,我们将在下面的部分中探讨这些特性。 @@ -911,6 +911,21 @@ class Product { } ``` +注: 此处如果设置了 `tconfig.json` 中的 [strictPropertyInitialization](https://www.typescriptlang.org/tsconfig#strictPropertyInitialization) 会产生警告。 + +可以使用以下例子: + +```jsx +class Product { + name: string; + unitPrice: number; + constructor(name: string, unitPrice: number) { + this.name = name; + this.unitPrice = unitPrice; + } +} +``` + 2. 我们使用`new`关键字后跟类名和括号来创建`Product`类的实例。然后,我们继续与类交互,设置属性值或调用方法: ```jsx @@ -1048,7 +1063,7 @@ class OrderDetail implements IOrderDetail { } ``` -# 扩展类 +# 继承类 类可以扩展其他类。这与扩展其他接口的接口的概念相同,我们在*扩展接口*一节中介绍了这一概念。这是一种与子类共享类属性和方法的方法。 @@ -1260,7 +1275,7 @@ console.log(table.unitPrice); 如果我们运行这个,我们应该在控制台中看到两个 0。 -# 静止的 +# 静态修饰符 静态属性和方法保存在类本身中,而不是类实例中。可以在属性或方法名称之前使用`static`关键字声明它们。 @@ -1333,9 +1348,9 @@ class OrderDetail { } ``` -编译器没有给我们任何抱怨。特别是,`OrderDetail`类中对`Product`接口的引用是可以解析的,即使它位于不同的文件中。这是因为`Product`和`OrderDetail`都在全球范围内。 +编译器没有给我们任何警告。特别是,`OrderDetail`类中对`Product`接口的引用是可以解析的,即使它位于不同的文件中。这是因为`Product`和`OrderDetail`都在全局范围内。 -在全局范围内操作是有问题的,因为项目名称可能会在不同的文件之间发生冲突,并且随着代码库的增长,这将很难避免。模块解决了这个问题,并帮助我们编写组织良好、可重用的代码。 +在全局范围内这样操作是存在问题的,因为项目名称可能会在不同的文件之间发生冲突,并且随着代码库的增长,这将很难避免。下一节的模块解决了这个问题,并帮助我们编写组织良好、可重用的代码。 # 模块格式 @@ -1350,7 +1365,7 @@ class OrderDetail { 在下面的部分(事实上,在这本书中),我们将使用 ES6 模块编写代码。 -# 出口 +# 导出模块 从模块导出代码允许其他模块使用它。为了从模块导出,我们使用了`export`关键字。我们可以指定在项目定义之前直接使用`export`导出项目。导出可以应用于接口、类型别名、类、函数、常量等。 @@ -1365,13 +1380,13 @@ export interface Product { } ``` -2. 在我们进行此更改后,编译器将抱怨对`OrderDetail`类中`Product`接口的引用: +2. 在我们进行此更改后,编译器对`OrderDetail`类中`Product`接口的引用将产生警告: ![](img/9f796565-f7ba-49c9-8306-7fdf77d57e23.png) -这是因为`Product`不再在全球范围内,但`OrderDetail`仍然在全球范围内。我们将在下一节中解决这个问题,但让我们先看看导出`Product`接口的其他方法。 +这是因为`Product`不再在全局范围内,但`OrderDetail`仍然在全局范围内。我们将在下一节中解决这个问题,但让我们先看看导出`Product`接口的其他方法。 -3. 我们可以在项目声明下面使用`export`语句。我们使用`export`关键字,后跟逗号分隔的项目名称列表,以大括号形式导出: +3. 我们也可以在项目声明下面使用`export`语句。我们使用`export`关键字,后跟逗号分隔的项目名称列表,以大括号形式导出: ```jsx interface Product { @@ -1393,7 +1408,7 @@ interface Product { export { Product as Stock } ``` -# 进口 +# 导入模块 导入允许我们从导出的模块导入项目。我们使用一个`import`语句来实现这一点,该语句包括要导入的项目名称(用大括号括起来)和从中获取项目的文件路径(不包括`ts`扩展名)。我们只能导入在其他模块文件中导出的项目。 @@ -1451,7 +1466,7 @@ import Product from "./product"; 我们需要先编译 TypeScript 代码,然后才能在浏览器中执行它。我们通过在要编译的文件上运行 TypeScript 编译器`tsc`来实现这一点。TypeScript 非常流行,在许多不同的情况下使用: * 它通常被引入到现有的大型 JavaScript 代码库中 -* 默认情况下,它出现在角度项目中 +* 默认情况下,它出现在 Angular 项目中 * 它通常用于向 React 项目添加强类型 * 它甚至可以在 Node.js 项目中使用 @@ -1503,11 +1518,11 @@ exports.OrderDetail = OrderDetail; 在接下来的部分中,我们将继续使用`orderDetail.ts`,探索如何配置编译器。 -# 共同选择 +# 可选参数 如前所述,TypeScript 编译器有很多配置选项。所有配置选项可在[找到 https://www.typescriptlang.org/docs/handbook/compiler-options.html](https://www.typescriptlang.org/docs/handbook/compiler-options.html) 。以下各节详细介绍了使用的一些更常见的选项。 -# --目标 +# --target 这决定了将在其中生成传输代码的 ECMAScript 版本。 @@ -1533,7 +1548,7 @@ export class OrderDetail { } ``` -# --奥特迪尔 +# --outDir 默认情况下,传输的 JavaScript 文件在与 TypeScript 文件相同的目录中创建。`--outDir`可用于将这些文件放在不同的目录中。 @@ -1545,15 +1560,15 @@ tsc orderDetail --outDir dist 将创建一个包含生成的`orderDetail.js`文件的`dist`文件夹。 -# --模块 +# --module 这指定生成的 JavaScript 应使用的模块格式。如果以 ES3 或 ES5 为目标,则默认为**CommonJS**模块格式。`ES6`和`ESNext`是当今创建新项目时的常见选项。 -# --允许 +# --enable 此选项告诉 TypeScript 编译器处理 JavaScript 文件和 TypeScript 文件。如果我们已经用 JavaScript 编写了一些代码,并且使用了尚未在所有浏览器中实现的功能,那么这将非常有用。在这种情况下,我们可以使用 TypeScript 编译器将我们的 JavaScript 转换成可以在更广泛的浏览器中使用的东西。 -# --监视 +# --watch 此选项使 TypeScript 编译器无限期运行。每当源文件发生更改时,编译过程将自动触发以生成新版本。在我们的开发过程中,这是一个有用的选项: @@ -1577,7 +1592,7 @@ getTotal(discount: number): number { 要退出监视模式,我们可以通过单击终端中的 bin 图标来终止终端。 -# --无 mplicitany +# --noImplicitAny 这迫使我们明确指定要使用它的`any`类型。这迫使我们思考我们对`any`的使用以及我们是否真的需要它。 @@ -1618,7 +1633,7 @@ doSomething(input: {something: () => void, result: string}) { 如果我们再次使用`--noImplicitAny`进行编译,编译器会很高兴。 -# --无 mplicitreturns +# --noImplicitReturns 这确保了如果返回类型不是`void`,我们在函数的所有分支中返回一个值。 @@ -1656,13 +1671,13 @@ tsc orderDetail --noImplicitReturns orderDetail.ts(9,31): error TS7030: Not all code paths return a value. ``` -# --源地图 +# --sourcemap 设置此选项后,将在透明过程中生成`*.map`文件。这将允许我们调试程序的 TypeScript 版本(而不是传输的 JavaScript)。因此,这通常在开发过程中打开。 -# --模溶液 +# --moduleResolution -这将告诉 TypeScript 编译器如何解析模块。可设置为`classic`或`node`。如果我们使用的是 ES6 模块,则默认为`classic`,这意味着 TypeScript 编译器很难找到第三方软件包,如 Axios。因此,我们可以显式地将其设置为`node`,告诉编译器在`"node_modules"`中查找模块。 +这将告诉 TypeScript 编译器如何解析模块。可设置为`classic`或`node`或指定版本 `node10`, `node16`, `nodenext`, or `bundler`。如果我们使用的是 ES6 模块,则默认为`classic`,这意味着 TypeScript 编译器很难找到第三方软件包,如 Axios。因此,我们可以显式地将其设置为`node`,告诉编译器在`"node_modules"`中查找模块。 # tsconfig.json @@ -1734,7 +1749,7 @@ tsc 因此,我们有很多选择来调整 TypeScript 编译器以适应我们的特殊情况。一些选项,例如`--noImplicitAny`,迫使我们编写好的 TypeScript 代码。通过在项目中引入 linting,我们可以将对代码的检查提升到下一个级别,我们将在下一节中介绍。 -# TypeScript 脱毛 +# TypeScript 精简 正如我们所看到的,编译器对我们的 TypeScript 代码进行了大量有用的检查,以帮助我们编写无错误的代码。我们可以更进一步,对代码进行精简,以帮助我们使代码更具可读性和可维护性。TSLint 是一种在 TypeScript 项目中非常流行的 linter,我们将在本节中探讨它。 @@ -1880,7 +1895,7 @@ export class OrderDetail { 在本章的开头,有一节介绍了我们为什么要使用 TypeScript 构建前端。我们现在有了 TypeScript 早期捕捉错误的第一手经验,并为我们提供了诸如 IntelliSense 之类的高效功能。我们了解到 TypeScript 只是 JavaScript 的一个扩展。因此,我们可以使用 JavaScript 中的所有功能以及 TypeScript 中的其他内容。其中一个附加功能是类型注释,它可以帮助编译器发现错误,并在代码编辑器中显示代码导航等功能。 -我们还没有涵盖所有关于类型的知识,但是我们现在有足够的知识来构建相当复杂的类型脚本程序。特别是类,使我们能够很好地对复杂的现实世界对象建模。我们学习了模块以及它们如何使我们远离危险的全球范围。模块允许我们很好地构造代码并使其可重用。如果我们需要支持 IE,我们甚至可以使用它们,因为它有神奇的 TypeScript 编译器。 +我们还没有涵盖所有关于类型的知识,但是我们现在有足够的知识来构建相当复杂的类型脚本程序。特别是类,使我们能够很好地对复杂的现实世界对象建模。我们学习了模块以及它们如何使我们远离危险的全局范围。模块允许我们很好地构造代码并使其可重用。如果我们需要支持 IE,我们甚至可以使用它们,因为它有神奇的 TypeScript 编译器。 我们了解了 TypeScript 编译器,以及它如何在不同的用例中工作,因为它是非常可配置的。这对于我们在本书后面开始使用带有 React 的 TypeScript 非常重要。