什么是 TypeScript?为什么我要用它代替 JavaScript?

您能描述一下 TypeScript 语言是什么吗?

JavaScript 或可用的库无法执行的工作是什么,这使我有理由考虑?

答案

我最初是在 TypeScript 仍然热销时写这个答案的。五年后,这是一个不错的概述,但请查看以下Lodewijk 的答案以获取更多深度

1000 英尺查看...

TypeScript是 JavaScript 的超集,主要提供可选的静态类型,类和接口。最大的好处之一是使 IDE 能够提供更丰富的环境,以便在键入代码时发现常见错误。

要了解我的意思,请观看有关该语言的Microsoft 入门视频

对于大型 JavaScript 项目,采用 TypeScript 可能会导致软件更强大,同时仍可以在运行常规 JavaScript 应用程序的地方进行部署。

它是开源的,但是如果您使用受支持的 IDE,则只有在键入时才能获得聪明的 Intellisense。最初,这只是 Microsoft 的 Visual Studio(也在Miguel de Icaza 的博客文章中提到)。 如今其他 IDE 也提供 TypeScript 支持

还有其他类似的技术吗?

CoffeeScript ,但这确实有不同的用途。恕我直言,CoffeeScript 为人类提供了可读性,但 TypeScript 还通过可选的静态类型为工具提供了深层的可读性(有关更多批评,请参阅此最新博客文章 )。还有Dart,但可以完全替代 JavaScript(尽管它可以生成 JavaScript 代码

例如,这是一些 TypeScript(您可以在TypeScript Playground 中使用它

class Greeter {
    greeting: string;
    constructor (message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

这是它将产生的 JavaScript

var Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

注意 TypeScript 如何定义成员变量和类方法参数的类型。转换为 JavaScript 时已将其删除,但 IDE 和编译器使用它来发现错误,例如将数字类型传递给构造函数。

它也能够推断出未明确声明的类型,例如,它将确定greet()方法返回一个字符串。

调试 TypeScript

许多浏览器和 IDE 通过 Sourcemap 提供直接调试支持。有关更多详细信息,请参见此堆栈溢出问题: 使用 Visual Studio 调试 TypeScript 代码

想知道更多?

我最初是在 TypeScript 仍然热销时写这个答案的。查看Lodewijk对这个问题的答案,以获取更多当前的详细信息。

TypeScript 与 JavaScript 的关系

打字稿是一个 JavaScript 的类型化超编译为普通的 JavaScript - typescriptlang.org

JavaScript 是由EMCA 技术委员会 39开发的一种编程语言,该委员会由许多不同的利益相关者组成。 TC39 是ECMA主办的委员会:内部标准组织。 JavaScript 由许多不同的供应商(例如 Google,Microsoft,Oracle 等)具有许多不同的实现。 JavaScript 的目标是成为网络上的通用语言。

TypeScript 是 JavaScript 语言的超集,具有单个开源编译器,并且主要由单个供应商 Microsoft 开发。 TypeScript 的目标是帮助通过类型系统尽早发现错误并提高 JavaScript 开发的效率。

本质上,TypeScript 通过三种方式实现其目标:

  1. 对现代 JavaScript 功能的支持 -JavaScript 语言(不是运行时)通过ECMAScript标准进行了标准化。并非所有的浏览器和 JavaScript 运行时都支持所有 ECMAScript 标准的所有功能(请参阅此概述 )。 TypeScript 允许使用许多最新的 ECMAScript 功能,并将其转换为您选择的较旧的 ECMAScript 目标(请参阅--target编译器选项下的编译目标列表)。这意味着您可以安全地使用新功能,例如模块,lambda 函数,类,扩展运算符和解构,同时保持与旧版浏览器和 JavaScript 运行时的向后兼容性。

  2. 高级类型系统 - 类型支持不是 ECMAScript 标准的一部分,并且可能永远不会由于 JavaScript 的解释性质而不是编译性质而引起。 TypeScript 的类型系统非常丰富,包括:接口,枚举,混合类型,泛型,并集 / 交集类型,访问修饰符等等。 TypeScript 的官方网站提供了这些功能的概述。 Typescript 的类型系统可与大多数其他类型的语言媲美,并且在某些情况下可以说更强大。

  3. 开发人员工具支持 -TypeScript 的编译器可以作为后台进程运行,以支持增量编译和 IDE 集成,因此您可以更轻松地导航,发现问题,检查可能性并重构代码库。

TypeScript 与其他 JavaScript 定位语言的关系

与其他可编译为 JavaScript 的语言相比,TypeScript 具有独特的理念。 JavaScript 代码是有效的 TypeScript 代码; TypeScript 是 JavaScript 的超集。您几乎可以将.js文件重命名为.ts文件,然后开始使用 TypeScript(请参见下面的 “JavaScript 互操作性”)。 TypeScript 文件被编译为可读的 JavaScript,因此可以向后移植,并且理解编译的 TypeScript 一点也不困难。 TypeScript 以 JavaScript 的成功为基础,同时改善了其缺点。

一方面,您拥有使用现代 ECMAScript 标准并将其编译为较旧的 JavaScript 版本的面向未来的工具,其中 Babel 是最受欢迎的工具。另一方面,您所使用的语言可能与针对 JavaScript 的 JavaScript 完全不同,例如 CoffeeScript,Clojure,Dart,Elm,Haxe,Scala.js,以及更多其他宿主(请参见此列表 )。这些语言虽然可能比 JavaScript 的未来可能会领先的地方要好,但冒着更大的风险,即找不到足够的采用以保证其未来。您可能还很难找到其中一些语言的经验丰富的开发人员,尽管您会发现这些语言通常会更热心。与 JavaScript 的互操作还可以更复杂一些,因为它们与 JavaScript 实际相去甚远。

TypeScript 位于这两个极端之间,因此可以平衡风险。从任何标准来看,TypeScript 都不是冒险的选择。如果您不熟悉 JavaScript,则只需花费很少的时间就可以习惯,因为它不是完全不同的语言,具有出色的 JavaScript 互操作性支持,并且最近已被广泛采用。

可选的静态类型和类型推断

JavaScript 是动态类型的。这意味着 JavaScript 在运行时实际实例化之前不知道变量的类型。这也意味着可能为时已晚。 TypeScript 为 JavaScript 添加了类型支持。如果正确使用卡牌(由您输入代码的严格程度或完全由您键入代码来决定),则可以完全消除由错误假设某个变量属于某种类型而导致的错误。

通过使用类型推断,TypeScript 使键入变得更容易,并且显式性更低。例如:TypeScript 中的var x = "hello"var x : string = "hello" 。类型仅是根据其用途推断出来的。即使您没有明确键入类型,它们仍然存在,可以避免您执行某些操作,否则将导致运行时错误。

默认情况下,可以选择键入 TypeScript。例如, function divideByTwo(x) { return x / 2 }是 TypeScript 中的有效函数,可以使用任何类型的参数调用,即使使用字符串调用它显然会导致运行时错误。就像您已经习惯 JavaScript。之所以行之有效,是因为当未明确分配任何类型并且无法推断类型时(例如在 divideByTwo 示例中),TypeScript 将隐式分配类型any 。这意味着 dividByTwo 函数的类型签名会自动变为function divideByTwo(x : any) : any 。有一个禁止该行为的编译器标志:-- --noImplicitAny 。启用此标志可以提高安全性,但也意味着您将不得不进行更多键入。

类型具有与之相关的成本。首先,有一个学习曲线,其次,当然,使用适当的严格类型来设置代码库也将花费您更多的时间。以我的经验,在与他人共享的任何严肃的代码库上,这些成本是完全值得的。 在 Github 中对编程语言和代码质量进行的大规模研究表明: “通常,静态类型的语言比动态类型的缺陷倾向性小,并且从相同的角度来看,强类型强于弱类型”。

有趣的是,这篇相同的论文发现 TypeScript 比 JavaScript 容易出错:

对于那些系数为正的用户,我们可以期望该语言与大量的缺陷修复程序相关联。这些语言包括 C,C ++, JavaScript ,Objective-C,Php 和 Python。 Clojure,Haskell,Ruby,Scala 和TypeScript等语言均具有负系数,这意味着这些语言导致缺陷修复提交的可能性低于平均值。

增强的 IDE 支持

TypeScript 的开发经验是对 JavaScript 的极大改进。 TypeScript 编译器会根据其丰富的类型信息实时通知 IDE。这提供了两个主要优点。例如,使用 TypeScript,您可以安全地进行重构,例如在整个代码库中进行重命名。通过代码完成,您可以获得有关库可能提供的任何功能的内联帮助。不再需要记住它们或在在线参考中查找它们。在您忙于编码时,编译错误将直接在 IDE 中以红色蠕变线报告。总而言之,与使用 JavaScript 相比,这可以显着提高生产率。一个人可以花费更多的时间进行编码,而花费较少的调试时间。

有很多对 TypeScript 都具有出色支持的 IDE,例如 Visual Studio Code,WebStorm,Atom 和 Sublime。

严格的空检查

形式的运行时错误cannot read property 'x' of undefinedundefined is not a function ,这通常是由 JavaScript 代码中的错误引起的。由于无法使用 TypeScript 编译器不知道的变量( any类型变量的属性除外),TypeScript 可以立即降低发生此类错误的可能性。仍然有可能错误地利用设置为undefined的变量。但是,使用 TypeScript 2.0 版,可以通过使用非空类型来一起消除这些类型的错误。其工作原理如下:

启用严格的空检查( --strictNullChecks编译器标志)后,TypeScript 编译器将不允许将undefined分配给变量,除非您明确声明其为可空类型。例如, let x : number = undefined将导致编译错误。因为undefined不是数字,所以这与类型理论非常吻合。可以将x定义为number的总和类型,然后将其undefinedundefined来纠正此问题: let x : number | undefined = undefined

一旦已知类型为可为空,即它的类型也可以为nullundefined ,则 TypeScript 编译器可以通过基于控制流的类型分析来确定您的代码是否可以安全地使用变量。换句话说,当您通过例如if语句检查变量是否undefined ,TypeScript 编译器将推断出代码控制流的该分支中的类型不再可以为 null,因此可以安全地使用。这是一个简单的示例:

let x: number | undefined;
if (x !== undefined) x += 1; // this line will compile, because x is checked.
x += 1; // this line will fail compilation, because x might be undefined.

在构建期间,TypeScript Anders Hejlsberg 的 2016 年会议联合设计师对此功能进行了详细说明和演示: 视频 (从 44:30 到 56:30)。

汇编

要使用 TypeScript,您需要一个构建过程来编译为 JavaScript 代码。构建过程通常仅需几秒钟,具体取决于项目的大小。 TypeScript 编译器支持增量编译( --watch编译器标志),以便可以以更高的速度编译所有后续更改。

TypeScript 编译器可以在生成的. js 文件中内联源地图信息,或创建单独的. map 文件。调试实用程序(例如 Chrome DevTools 和其他 IDE)可以使用源地图信息,以将 JavaScript 中的行与在 TypeScript 中生成它们的行相关联。这使您可以在运行时直接在 TypeScript 代码上设置断点和检查变量。源地图信息的效果很好,距 TypeScript 尚有很长时间,但调试 TypeScript 通常不如直接使用 JavaScript 那样好。以this关键字为例。由于自 ES2015 以来闭包周围的this关键字的语义已更改, this在运行时此变量实际上可能作为名为_this的变量存在(请参阅此答案 )。这可能会在调试过程中使您感到困惑,但是如果您了解或检查 JavaScript 代码,通常不会出现问题。应当指出,巴别塔也遭受同样的问题。

TypeScript 编译器还可以完成其他一些技巧,例如基于装饰器生成拦截代码,为不同模块系统生成模块加载代码以及解析JSX 。但是,除了 Typescript 编译器之外,您可能还需要构建工具。例如,如果要压缩代码,则必须在构建过程中添加其他工具。

有 TypeScript 编译插件可用于WebpackGulpGrunt以及几乎所有其他 JavaScript 构建工具。 TypeScript 文档中有一节介绍如何涵盖所有内容的构建工具集成 。如果您想要更多的构建时间检查,也可以使用lint 。还有大量的种子项目,可以带您开始使用 TypeScript 并结合其他许多技术,例如 Angular 2,React,Ember,SystemJS,Webpack,Gulp 等。

JavaScript 互操作性

由于 TypeScript 与 JavaScript 紧密相关,因此具有强大的互操作性功能,但是要使用 TypeScript 中的 JavaScript 库,还需要做一些额外的工作。需要TypeScript 定义 ,以便 TypeScript 编译器理解_.groupByangular.copy$.fadeOut类的函数调用实际上并非非法语句。这些功能的定义位于.d.ts文件中。

定义可以采用的最简单形式是允许以任何方式使用标识符。例如,当使用Lodash 时 ,单个行定义文件declare var _ : any将允许您调用_想要的任何函数,但是,当然,您仍然会犯错误: _.foobar()会是合法的 TypeScript 调用,但在运行时当然是非法的调用。如果您需要适当的类型支持和代码完成功能,则您的定义文件需要更加精确(有关示例,请参见lodash 定义 )。

TypeScript 编译器会自动理解预先打包有自己的类型定义的Npm 模块 (请参阅文档 )。对于几乎任何其他不包含自己的定义的半流行 JavaScript 库,已经有人通过另一个 npm 模块提供了类型定义。这些模块以 “@ types /” 为前缀,并来自名为DefinitelyTyped的 Github 存储库。

有一个警告:类型定义必须与您在运行时使用的库的版本匹配。如果不存在,TypeScript 可能会禁止您调用函数或取消引用存在的变量,或者允许您调用函数或取消引用不存在的变量,仅因为类型与编译时的运行时不匹配。因此,请确保为所使用的库的正确版本加载正确的类型定义版本。

老实说,这样做有点麻烦,这可能是您不选择 TypeScript 的原因之一,而是选择了 Babel 之类的东西,而该东西完全不需要获取类型定义。另一方面,如果您知道自己在做什么,则可以轻松解决由于定义文件不正确或丢失而引起的任何类型的问题。

从 JavaScript 转换为 TypeScript

任何.js文件都可以重命名为.ts文件,并通过 TypeScript 编译器运行,以在语法上获得与输出相同的 JavaScript 代码(如果从语法上说正确的话)。即使 TypeScript 编译器遇到编译错误,它仍然会生成.js文件。它甚至可以通过--allowJs标志接受.js文件作为输入。这使您可以立即从 TypeScript 开始。不幸的是,编译错误很可能在一开始就发生。确实需要记住,这些并不是停止显示的错误,就像您可能习惯于其他编译器一样。

TypeScript 的性质不可避免地会在将 JavaScript 项目转换为 TypeScript 项目时开始出现编译错误。 TypeScript 检查所有代码的有效性,因此需要了解所有使用的函数和变量。因此,必须对所有类型都使用类型定义,否则必然会发生编译错误。如上一章所述,对于几乎所有 JavaScript 框架,都有.d.ts文件,可以通过安装DefinitelyTyped 包轻松获取。但是,可能是因为您使用了一些晦涩的库,而其中没有 TypeScript 定义可用,或者您已经填充了一些 JavaScript 原语。在这种情况下,必须为这些位提供类型定义,以使编译错误消失。只需创建一个.d.ts文件并将其包含在 tsconfig.json 的files数组中,以便 TypeScript 编译器始终考虑该文件。在其中将 TypeScript 不知道的那些位声明为any类型。消除所有错误后,您可以根据需要逐步在这些部分中键入内容。

为了使 TypeScript 进入构建管道,还需要进行一些(重新)配置构建管道的工作。正如在编译一章中提到的那样,那里有很多好的资源,我鼓励您寻找使用您要使用的工具组合的种子项目。

最大的障碍是学习曲线。我鼓励您起初先做一个小项目。看看它是如何工作的,它是如何构建的,它使用的是哪个文件,它是如何配置的,在 IDE 中是如何运行的,它是如何结构的,它使用的是什么工具等。将大型 JavaScript 代码库转换为 TypeScript 是可行的,只要您知道你在做什么。阅读此博客,例如有关在 72 小时内将 60 万行转换为打字稿的信息 。进行跳跃之前,请确保您已掌握该语言。

采用

TypeScript 是开源的(Apache 2 许可,请参见GitHub ),并得到 Microsoft 的支持。 C#的首席架构师Anders Hejlsberg负责该项目。这是一个非常活跃的项目。在过去的几年中,TypeScript 团队已经发布了许多新功能,并且仍然计划推出许多出色的功能(请参阅路线图 )。

有关采用和普及的一些事实:

TypeScript 的作用类似于 CSS 的 less 或 sass。它们是它的超级集,这意味着您编写的每个 JS 代码都是有效的 TypeScript 代码。另外,您可以使用它添加到语言中的其他优点,并且转译后的代码将是有效的 js。您甚至可以设置要在其上生成结果代码的 JS 版本。

当前 TypeScript 是 ES2015 的超集,因此可能是开始学习新 js 功能并转换为项目所需标准的一个不错的选择。

TypeScript 基础知识 ” - Dan WahlinJohn Papa的 Pluralsight 视频课程非常好,目前(2016 年 3 月 25 日)已更新,以反映 TypeScript 1.8(Typescript 简介)。

对我来说,除了智能感知的好可能性之外,真正好的功能还包括接口模块 ,实现 AMD 的简易性以及在通过 IE 调用时使用 Visual Studio Typescript 调试器的可能性。

总结 :如果按预期使用 TypeScript,可以使 JavaScript 编程更可靠,更容易。在整个 SDLC 上,它可以显着提高 JavaScript 程序员的生产率。

所有浏览器均支持并预先编译的 Ecma 脚本 5(ES5)。 ES6 / ES2015 和 ES / 2016 今年进行了很多更改,因此要弹出这些更改,请务必谨慎之间使用 TypeScript。

•TypeScript 是类型 -> 意味着我们必须定义每个属性和方法的数据类型。如果您知道 C#,那么 Typescript 很容易理解。

•TypeScript 的一大优势是我们可以在投入生产之前及早识别与类型相关的问题。如果类型不匹配,这会使单元测试失败。