什么是TypeScript,为什么我会用它来代替JavaScript?

你能否描述一下TypeScript语言?

JavaScript或者可用的库不能做什么,这会给我有理由去考虑它?


我最初编写这个答案时,Typescript仍然热门新闻。 五年后,这是一个好的概述,但请看下面Lodewijk的答案以获得更深入的了解

1000英尺的视野...

TypeScript是JavaScript的超集,主要提供可选的静态类型,类和接口。 其中一个很大的好处是可以让IDE在键入代码时提供更丰富的环境来查找常见错误。

要了解我的意思,请观看微软关于该语言的介绍性视频。

对于大型JavaScript项目,采用TypeScript可能会产生更强大的软件,同时仍可在常规JavaScript应用程序运行的位置部署。

它是开源的,但如果您使用受支持的IDE,则只会在键入时获得智能Intellisense。 最初,这只是微软的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()方法返回一个字符串。

调试打字稿

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

想知道更多?

我最初编写这个答案时,Typescript仍然热门新闻。 查看Lodewijk针对这个问题的答案,了解更多当前细节。


尽管接受的答案没有问题,但我觉得现在确实没有TypeScript正义。 现在不再是早期了。 现在TypeScript正在用TypeScript编写几种流行的框架,现在发现更多的采用。 现在你应该选择TypeScript而不是JavaScript。

与JavaScript的关系

JavaScript通过ECMAScript标准进行了标准化。 并非所有正在使用的浏览器都支持新的ECMAScript标准的所有功能(请参阅此表格)。 TypeScript支持新的ECMAScript标准,并将它们编译为您选择的(较旧的)ECMAScript目标(当前目标为3,5和6 [2015年])。 这意味着您可以使用ES2015及更高版本的功能,比如今天的模块,lambda函数,类,扩展运算符,解构。 它还增加了当然的类型支持,这不是任何ECMAScript标准的一部分,并且可能永远不会由于解释性质而不是JavaScript的编译本质。 TypeScript的类型系统相对丰富,包括:接口,枚举,混合类型,泛型,联合和交集类型,访问修饰符等等。 TypeScript的官方网站给出了这些功能的概述。

与其他JavaScript定位语言的关系

与编译为JavaScript的其他语言相比,TypeScript具有独特的理念。 JavaScript代码是有效的TypeScript代码; TypeScript是JavaScript的超集。 几乎可以将.js文件重命名为.ts文件并开始使用TypeScript。 TypeScript文件被编译为可读的JavaScript,因此可以回迁,并且理解编译后的TypeScript并不难。 通过这种方式,TypeScript建立在JavaScript的成功之上,同时改进了其弱点。

一方面,您拥有未来的验证工具,可以采用现代ECMAScript标准,并将其编译为较旧的JavaScript版本,其中Babel是最流行的版本。 另一方面,您的语言可能完全不同于JavaScript,比如Coffeescript,Clojure,Dart,Elm,Haxe,ScalaJs以及更多的整体主机(请参阅此列表)。 这些语言虽然可能比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类型。 这意味着divideByTwo函数的类型签名会自动变为function divideByTwo(x : any) : any 。 有一个编译器标志禁止这种行为:-- --noImplicitAny 。 启用此标志可提高您的安全性,但也意味着您必须进行更多打字。

类型有与他们相关的成本。 首先有一条学习曲线,其次,当然,使用适当的严格输入也会花费更多时间来设置代码库。 根据我的经验,这些成本完全值得您与其他人共享的任何严肃的代码库。 Github对编程语言和代码质量的大规模研究表明:“静态类型语言通常比动态类型缺陷容易,并且强类型优于弱类型。

值得注意的是,这篇相同的论文发现,TypeScript在JavaScript方面不太容易出错:

对于那些系数为正数的人,我们可以预料,语言与其他条件相关联的是更多的缺陷修复。 这些语言包括C,C ++,JavaScript,Objective-C,Php和Python。 Clojure,Haskell,Ruby,Scala和TypeScript语言都具有负面系数,这意味着这些语言不太可能导致缺陷修复提交。

增强的IDE支持

使用TypeScript的开发经验是JavaScript的重大改进。 IDE通过TypeScript编译器实时通知其丰富类型信息。 这提供了几个主要优势。 例如,使用TypeScript,您可以安全地进行重构,比如整个代码库中的重命名。 通过代码完成,您可以获得关于图书馆可能提供的任何函数的内联帮助。 不再需要记住它们或在线参考中查找它们。 编译错误直接在IDE中用红色波浪线报告,而您正忙于编码。 总之,与使用JavaScript相比,这可以显着提高工作效率。 人们可以花更多时间编码,而且调试时间更短。

有很多IDE对TypeScript有很好的支持,比如Visual Studio&VS代码,Atom,Sublime和IntelliJ / WebStorm。

严格的空检查

表单的运行时错误cannot read property 'x' of undefinedundefined is not a function通常是由JavaScript代码中的错误引起的。 开箱即用的TypeScript已经降低了发生这类错误的可能性,因为不能使用TypeScript编译器不知道的变量( any类型变量的属性除外)。 尽管错误地使用设置为undefined的变量仍然是可能的。 但是,使用TypeScript的2.0版本,您可以通过使用不可空类型来消除这些类型的错误。 这工作如下:

如果启用了严格的空检查( --strictNullChecks编译器标志),TypeScript编译器将不允许将undefined分配给变量,除非您明确声明它为可空类型。 例如, let x : number = undefined将导致编译错误。 这完全符合类型理论,因为undefined不是一个数字。 可以将x定义为number的总和类型,并且可以用undefined来纠正: let x : number | undefined = undefined let x : number | undefined = undefined

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

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.

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

汇编

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

TypeScript编译器可以在生成的.js文件中内联源地图信息或创建单独的.map文件。 源地图信息可以通过像Chrome DevTools和其他IDE这样的调试工具来使用,以将JavaScript中的行与在TypeScript中生成它们的行关联起来。 这使您可以在运行时直接在TypeScript代码上设置断点并检查变量。 源地图信息工作得很好,大约在TypeScript之前,但调试TypeScript通常不如直接使用JavaScript时那么好。 this关键字为例。 由于改变了语义的this关键字封左右,因为ES2015, this实际上可能运行时间为变量,名为中存在_this (见这个答案)。 在调试过程中,这可能会让您感到困惑,但如果您了解它或检查JavaScript代码通常不会造成问题。 应该指出的是,巴贝尔遭受同样的问题。

还有一些TypeScript编译器可以执行的其他技巧,比如生成基于装饰器的截取代码,为不同的模块系统生成模块加载代码并解析JSX。 但是,除了Typescript编译器之外,您可能还需要构建工具。 例如,如果你想压缩你的代码,你将不得不在你的构建过程中添加其他工具来这样做。

Webpack,Gulp,Grunt和几乎所有其他JavaScript构建工具都可以使用TypeScript编译插件。 TypeScript文档有一个关于集成所有构建工具的章节。 如果您想要更多的构建时间检查,还可以使用linter。 还有大量的种子项目可以让你开始使用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 /”,来自Github存储库,名为DefinitelyTyped。

有一个警告:类型定义必须与运行时使用的库的版本相匹配。 如果他们不这样做,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是非常可行的知道你在做什么,但是当你不这样做时可能会感到沮丧。

采用

TypeScript是开源的(Apache 2许可,请参阅github)并由Microsoft支持。 C#的首席架构师Anders Hejlsberg领导该项目。 这是一个非常活跃的项目; 在过去的几年里,TypeScript团队发布了许多新功能,并且还有很多很棒的功能(参见路线图)。

在2017年的StackOverflow开发者调查中,TypeScript是最受欢迎的JavaScript编译器(总共排名第9),并在最受欢迎的编程语言类别中获得第三名。


TypeScript的功能与CSS或sass的功能类似。 它们是它的超集,这意味着你编写的每个JS代码都是有效的TypeScript代码。 另外,您可以使用它添加到语言中的其他好东西,并且传输的代码将是有效的js。 你甚至可以设置你想要的结果代码的JS版本。

目前TypeScript是ES2015的超级套装,因此可能是一个很好的选择,可以开始学习新的js功能并将其转换为项目所需的标准。

链接地址: http://www.djcxy.com/p/17003.html

上一篇: What is TypeScript and why would I use it in place of JavaScript?

下一篇: Why aren't ◎ܫ◎ and ☺ valid JavaScript variable names?