你可能听说过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
然后你应该在你的编辑器中得到一些斜线的红色错误,突出我们的错误,如下图。
你还应该在左下角看到一个十字,旁边有一个二。点击它将显示出被发现的问题。
虽然你不在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.ts 和querySelector<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中,像1 或2.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') ,返回的对象是类型HTMLImageElement 。HTMLImageElement 有一个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集成)。
- 检查JavaScript文件(
checkJs选项)。 - 假设我们在ES2015环境下构建(
target选项)。默认为ES2015意味着我们可以使用像承诺这样的东西,而TypeScript不会给我们带来错误。 - 不输出任何编译的文件(
noEmit选项)。当你在TypeScript源文件中编写TypeScript代码时,你需要编译器为你生成JavaScript代码以在浏览器中运行。由于我们正在编写在浏览器中运行的JavaScript代码,我们不需要编译器为我们生成任何文件。 - 最后,
include: ["*.js"],指示TypeScript查看根目录下的任何JavaScript文件。
现在我们有了这个文件,你可以将你的命令行指令更新为这样。
npx tsc -p jsconfig.json
这将用我们的配置文件运行编译器(这里的-p 是 "项目 "的简称),所以你在运行TypeScript时不再需要传递所有这些标志。
继续阅读《TypeScript初学者教程》(A Step by Step TypeScript Tutorial for Beginners):SitePoint。