面向初学者的TypeScript教程,一步一步来

104 阅读9分钟

A Step by Step TypeScript Tutorial for Beginners

你可能听说过TypeScript--由微软创建和维护的语言,它对网络产生了巨大的影响,许多著名的项目接受并将其代码迁移到TypeScript。TypeScript是JavaScript的一个类型化超集。换句话说,它为JavaScript增加了类型--因此得名。但是,为什么你会想要这些类型?它们能带来什么好处?你是否需要重写你的整个代码库来利用它们?这些问题,以及更多的问题,将在这个面向初学者的TypeScript教程中得到解答。

我们假设你对JavaScript及其工具有基本的了解,但不需要对TypeScript有任何了解就可以跟着学。

一些错误的JavaScript代码

首先,让我们看看一些相当标准的普通JavaScript代码,你可能在任何特定的代码库中遇到。它从Pexels API中获取了一些图片,并将它们插入到DOM中。

然而,这段代码中有几个错字,会导致问题。看看你是否能发现它们。

const PEXELS_API_KEY = '...';

async function fetchImages(searchTerm, perPage) {
  const result = await fetch(`https://api.pexels.com/v1/search?query=${searchTerm}&per_page=${perPage}`, {
    headers: {
      Authorization: PEXELS_API_KEY,
    }
  });
  const data = await result.json();

  const imagesContainer = document.qerySelector('#images-container');
  for (const photo of data.photos) {
    const img = document.createElement('image');
    img.src = photo.src.medium;
    imagesContainer.append(img);
  }
}

fetchImages('dogs', 5);
fetchImages(5, 'cats');
fetchImages('puppies');

你能发现上述例子中的问题吗?当然,如果你在浏览器中运行这段代码,你会立即得到错误,但通过利用TypeScript的优势,我们可以让TypeScript在编辑器中发现这些问题,从而更快地得到错误。

缩短这个反馈循环是很有价值的--而且随着项目规模的扩大,它的价值也越来越大。在这30行代码中发现错误很容易,但如果你在一个有几千行的代码库中工作呢?那时你会轻易发现任何潜在的问题吗?

注意:不需要从Pexels获得API密钥来跟随这个TypeScript教程。但是,如果你想运行代码,API密钥是完全免费的:你只需要注册一个账户,然后生成一个。

从编辑器中运行TypeScript

曾几何时,TypeScript要求所有文件都写成.ts 。但如今,入职坡道更顺畅了。你不需要TypeScript文件来编写TypeScript代码:相反,我们可以在任何我们喜欢的JavaScript文件上运行TypeScript!

如果你是VS Code的用户(如果你不是--我们会告诉你的!),这将是开箱即用,没有额外的要求。我们可以通过在我们的JavaScript文件的最上面添加这个来启用TypeScript的检查(重要的是它是第一行)。

// @ts-check

然后你应该在你的编辑器中得到一些斜线的红色错误,突出我们的错误,如下图。

TypeScript showing errors in VS Code

你还应该在左下角看到一个十字,旁边有一个二。点击它将显示出被发现的问题。

Errors displayed in the VS Code console

虽然你不在VS Code上,但并不意味着你不能获得同样的TypeScript高亮错误的体验。现在大多数编辑器都支持语言服务器协议(通常被称为LSP),这也是VS Code用来支持其TypeScript集成的原因。

值得在网上搜索,以找到你的编辑器和推荐的插件来设置它。

在本地安装和运行TypeScript

如果你不在VS Code上,或者你想要一个通用的解决方案,你也可以在命令行上运行TypeScript。在这一节中,我将告诉你如何做。

首先,让我们生成一个新的项目。这一步假设你的机器上安装了Node和npm

mkdir typescript-demo
cd typescript demo
npm init -y

接下来,将TypeScript添加到你的项目中。

npm install --save-dev typescript

注意:你可以在你的机器上全局安装TypeScript,但我喜欢按项目安装。这样,我就可以确保我可以控制每个项目所使用的TypeScript的确切版本。如果你有一个项目很久没有碰过了,这很有用;你可以在这个项目上继续使用旧的TS版本,同时让新的项目使用较新的版本。

一旦安装完毕,你可以运行TypeScript编译器(tsc),得到同样的错误(不要担心这些额外的标志,因为我们很快会更多地讨论它们)。

npx tsc index.js --allowJs --noEmit --target es2015
index.js:13:36 - error TS2551: Property 'qerySelector' does not exist on type 'Document'. Did you mean 'querySelector'?

13   const imagesContainer = document.qerySelector('#images-container');
                                      ~~~~~~~~~~~~

  node_modules/typescript/lib/lib.dom.d.ts:11261:5
    11261     querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'querySelector' is declared here.

index.js:16:9 - error TS2339: Property 'src' does not exist on type 'HTMLElement'.

16     img.src = photo.src.medium;
           ~~~

Found 2 errors.

你可以看到,TypeScript在命令行中突出显示了与VS Code在上面的截图中突出显示的相同的JavaScript代码错误。

修复我们的JavaScript代码中的错误

现在,我们已经启动并运行了TypeScript,让我们来看看如何理解并纠正TypeScript标记的错误。

让我们看看我们的第一个错误。

属性qerySelector 不存在于类型上Document

index.js:13:36 - error TS2551: Property 'qerySelector' does not exist on type 'Document'. Did you mean 'querySelector'?

13   const imagesContainer = document.qerySelector('#images-container');

  node_modules/typescript/lib/lib.dom.d.ts:11261:5
    11261     querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'querySelector' is declared here.

如果你不习惯阅读TypeScript的错误,这可能看起来很难受,所以如果它看起来有点奇怪,不要惊慌TypeScript发现,在13 行,我们调用了一个方法document.qerySelector 。我们的意思是document.querySelector ,但是在打字的时候犯了一个错误。当我们试图在浏览器中运行我们的代码时,我们会发现这一点,但TypeScript能够让我们更早地意识到这一点。

下一部分,它强调了lib.dom.d.tsquerySelector<K...> 函数,这是深入到更高级的 TypeScript 代码,所以先不要担心,但在高层次上,这是 TypeScript 在向我们展示,它理解有一个叫做querySelector 的方法,而且它怀疑我们可能想要这个方法。

现在让我们放大上面错误信息的最后部分。

index.js:13:36 - error TS2551: Property 'qerySelector' does not exist on type 'Document'. Did you mean 'querySelector'?

具体来说,我想看看did not exist on type 'Document' 这个文本。在TypeScript中(大致上在每一种类型的语言中),项目有一个叫做type

在TypeScript中,像12.5 这样的数字有类型number ,像"hello world" 这样的字符串有类型string ,而一个HTML元素的实例有类型HTMLElement 。这就是TypeScript的编译器能够检查我们的代码是否合理的原因。一旦它知道了某个东西的类型,它就知道你可以调用哪些函数来获取这个东西,或者它上面存在哪些方法。

注意:如果你想了解更多关于数据类型的信息,请参考 "数据类型介绍"。静态、动态、强和弱"。

在我们的代码中,TypeScript看到我们提到了document 。这是浏览器中的一个全局变量,TypeScript知道这一点,并且知道它的类型是Document 。这个类型记录了(如果你原谅我的双关语!)我们可以调用的所有方法。这就是为什么TypeScript知道querySelector 是一个方法,而拼错的qerySelector 则不是。

当我们通过进一步的TypeScript教程 ,我们会看到更多的这些类型,但这是TypeScript所有的力量来自于此。很快我们就会定义我们自己的类型,这意味着我们真的可以扩展类型系统来了解我们所有的代码,以及我们在代码库中的任何特定对象可以做什么和不可以做什么。

现在让我们把注意力转移到下一个错误上,这个错误稍微有点不清楚。

属性src 不存在于类型上HTMLElement

index.js:16:9 - error TS2339: Property 'src' does not exist on type 'HTMLElement'.

16     img.src = photo.src.medium;

这是其中的一个错误,有时你必须在错误的上方寻找问题的所在。我们知道,HTML图像元素确实有一个src 属性,那么为什么TypeScript没有呢?

const img = document.createElement('image');
img.src = photo.src.medium;

这里的错误在第一行:当你创建一个新的图像元素时,你必须调用document.createElement('img') (因为HTML标签是<img> ,不是<image> )。一旦我们这样做,错误就会消失,因为TypeScript知道,当你调用document.createElement('img') ,你会得到一个具有src 属性的元素。而这一切都归结于类型

当你调用document.createElement('div') ,返回的对象是HTMLDivElement 的类型。当你调用document.createElement('img') ,返回的对象是类型HTMLImageElementHTMLImageElement 有一个src 的属性声明,所以TypeScript知道你可以调用img.src 。但是HTMLDivElement 没有,所以TypeScript会出错。

document.createElement('image') 的情况下,因为TypeScript不知道任何带有标签image 的HTML元素,它将返回一个类型为HTMLElement 的对象(一个通用的HTML元素,不特定于一个标签),它也缺乏src 属性。

一旦我们修正了这两个错误并重新运行TypeScript,你会看到我们没有得到任何回报,这表明没有任何错误。如果你已经将编辑器配置为显示错误,希望现在没有显示。

如何配置TypeScript

在每个文件中添加// @ts-check ,当我们在终端运行命令时还要添加那些额外的标志,这有点麻烦。TypeScript让你通过创建一个jsconfig.json 文件来代替在JavaScript项目中启用它。

在我们项目的根目录下创建jsconfig.json ,并把这个放在里面。

{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "target": "es2015"
  },
  "include": ["*.js"]
}

这将配置TypeScript编译器(和你的编辑器的TS集成)。

  1. 检查JavaScript文件(checkJs 选项)。
  2. 假设我们在ES2015环境下构建(target 选项)。默认为ES2015意味着我们可以使用像承诺这样的东西,而TypeScript不会给我们带来错误。
  3. 不输出任何编译的文件(noEmit 选项)。当你在TypeScript源文件中编写TypeScript代码时,你需要编译器为你生成JavaScript代码以在浏览器中运行。由于我们正在编写在浏览器中运行的JavaScript代码,我们不需要编译器为我们生成任何文件。
  4. 最后,include: ["*.js"] ,指示TypeScript查看根目录下的任何JavaScript文件。

现在我们有了这个文件,你可以将你的命令行指令更新为这样。

npx tsc -p jsconfig.json

这将用我们的配置文件运行编译器(这里的-p 是 "项目 "的简称),所以你在运行TypeScript时不再需要传递所有这些标志。

继续阅读《TypeScript初学者教程》(A Step by Step TypeScript Tutorial for Beginners):SitePoint