恭喜你选择 TypeScript 作为你的第一语言之一——你已经做出了正确的决定!
你可能已经听说 TypeScript 是 JavaScript (JS) 的“风格”或“变体”。TypeScript (TS) 和 JavaScript (JS) 之间的关系在现代编程语言中是独一无二的,因此更多地了解这种关系将帮助你理解 TypeScript 如何添加到 JavaScript 中。
什么是 JavaScript?简史
JavaScript(也称为 ECMAScript)最初是一种简单的浏览器脚本语言。在发明之初,它被期望用于嵌入在网页中的短代码片段——编写几十行以上的代码会有些不同寻常。因此,早期的网络浏览器执行此类代码的速度非常慢。然而,随着时间的推移,JS 变得越来越流行,网络开发者开始使用它创建交互式体验。
网络浏览器开发者通过优化其执行引擎(动态编译)和扩展其功能(添加 API)来应对 JS 使用量的增加,这反过来又让网络开发者更多地使用它。在现代网站上,你的浏览器经常运行跨越数十万行代码的应用程序。这是“网络”漫长而渐进的增长,它从一个简单的静态页面网络开始,演变成一个适用于各种丰富应用程序的平台。
更重要的是,JS 已变得足够流行,可以在浏览器环境之外使用,例如使用 node.js 实现 JS 服务器。“随处运行”的 JS 特性使其成为跨平台开发的理想选择。如今,许多开发者仅使用 JavaScript 来编程他们的整个堆栈!
总之,我们有一种专为快速使用而设计的语言,然后发展成为一种编写数百万行应用程序的成熟工具。每种语言都有其自身的怪癖——奇异之处和意外之处,而 JavaScript 的卑微开端使其拥有许多这样的怪癖。一些示例
-
JavaScript 的相等运算符 (
==) 强制转换其操作数,导致意外的行为jsif ("" == 0) {// It is! But why??}if (1 < x < 3) {// True for *any* value of x!} -
JavaScript 还允许访问不存在的属性
jsconst obj = { width: 10, height: 15 };// Why is this NaN? Spelling is hard!const area = obj.width * obj.heigth;
大多数编程语言会在出现此类错误时抛出错误,有些会在编译期间(在任何代码运行之前)这样做。在编写小型程序时,此类怪癖令人讨厌但可控;在编写包含数百或数千行代码的应用程序时,这些持续的意外是一个严重的问题。
TypeScript:静态类型检查器
我们之前说过,有些语言根本不允许那些有缺陷的程序运行。在不运行代码的情况下检测代码中的错误被称为静态检查。根据被操作的值的类型来确定什么是错误,什么是正确的被称为静态类型检查。
TypeScript 在执行之前检查程序中的错误,并且根据值的类型进行检查,使其成为一个静态类型检查器。例如,上面的最后一个示例由于 obj 的类型而存在错误。以下是 TypeScript 发现的错误
tsTryconstobj = {width : 10,height : 15 };constProperty 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'?2551Property 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'?area =obj .width *obj .; heigth
JavaScript 的类型化超集
那么 TypeScript 与 JavaScript 有什么关系呢?
语法
TypeScript 是一种语言,是 JavaScript 的超集:因此 JS 语法是合法的 TS。语法是指我们编写文本以形成程序的方式。例如,此代码存在语法错误,因为它缺少 )
tsTrylet')' expected.1005')' expected.a = (4
TypeScript 不会因为语法而将任何 JavaScript 代码视为错误。这意味着你可以获取任何可用的 JavaScript 代码并将其放入 TypeScript 文件中,而无需担心它的具体编写方式。
类型
然而,TypeScript 是一个类型化超集,这意味着它添加了有关如何使用不同类型的值的规则。有关 obj.heigth 的早期错误不是语法错误:它是以不正确的方式使用某种值(类型)的错误。
作为另一个示例,这是可以在浏览器中运行的 JavaScript 代码,它将记录一个值
jsconsole.log(4 / []);
这个语法合法的程序记录了 Infinity。然而,TypeScript 认为数字除以数组是一个无意义的操作,并将发出一个错误
tsTryThe right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.2363The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.console .log (4 /[] );
你可能确实打算将一个数字除以一个数组,也许只是想看看会发生什么,但大多数情况下,这是一个编程错误。TypeScript 的类型检查器旨在允许正确的程序通过,同时尽可能多地捕获常见错误。(稍后,我们将了解可用于配置 TypeScript 如何严格检查代码的设置。)
如果你将一些代码从 JavaScript 文件移动到 TypeScript 文件,你可能会看到类型错误,具体取决于代码的编写方式。这些可能是代码的合法问题,或者 TypeScript 过于保守。在整个指南中,我们将演示如何添加各种 TypeScript 语法以消除此类错误。
运行时行为
TypeScript 也是一种保留 JavaScript 的运行时行为的编程语言。例如,在 JavaScript 中除以零会产生 Infinity,而不是抛出运行时异常。作为一个原则,TypeScript 从不改变 JavaScript 代码的运行时行为。
这意味着,如果你将代码从 JavaScript 移动到 TypeScript,它保证以相同的方式运行,即使 TypeScript 认为代码有类型错误。
与 JavaScript 保持相同的运行时行为是 TypeScript 的基本承诺,因为它意味着你可以在两种语言之间轻松转换,而不用担心可能使你的程序停止工作的细微差别。
已擦除的类型
粗略地说,一旦 TypeScript 的编译器完成对代码的检查,它就会擦除类型以生成结果“已编译”的代码。这意味着一旦编译代码,生成的纯 JS 代码就没有类型信息。
这也意味着 TypeScript 永远不会根据它推断的类型来更改程序的行为。底线是,虽然您可能会在编译期间看到类型错误,但类型系统本身对程序在运行时的工作方式没有影响。
最后,TypeScript 不提供任何其他运行时库。您的程序将使用与 JavaScript 程序相同的标准库(或外部库),因此无需学习其他 TypeScript 特定的框架。
学习 JavaScript 和 TypeScript
我们经常看到这样的问题:“我应该学习 JavaScript 还是 TypeScript?”。
答案是,不学习 JavaScript 就无法学习 TypeScript!TypeScript 与 JavaScript 共享语法和运行时行为,因此您学习 JavaScript 的任何内容同时也在帮助您学习 TypeScript。
有很多资源可供程序员学习 JavaScript;如果您正在编写 TypeScript,则不应忽略这些资源。例如,标记为javascript的 StackOverflow 问题比标记为typescript的问题多大约 20 倍,但所有javascript问题也适用于 TypeScript。
如果您发现自己正在搜索“如何在 TypeScript 中对列表进行排序”之类的内容,请记住:TypeScript 是具有编译时类型检查器的 JavaScript 运行时。您在 TypeScript 中对列表进行排序的方式与在 JavaScript 中进行排序的方式相同。如果您找到直接使用 TypeScript 的资源,那也很棒,但不要局限于认为您需要 TypeScript 特定的答案来回答有关如何完成运行时任务的日常问题。
下一步
这是 TypeScript 日常使用语法和工具的简介。从这里,你可以