【问题标题】:What is TypeScript and why would I use it in place of JavaScript? [closed]什么是 TypeScript,我为什么要用它来代替 JavaScript? [关闭]
【发布时间】:2021-10-08 08:42:39
【问题描述】:

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

有什么是 JavaScript 或可用库无法做到的,这让我有理由考虑它?

【问题讨论】:

标签: javascript typescript


【解决方案1】:

TypeScript 与 JavaScript 的关系

TypeScript 是 JavaScript 的类型化超集,可编译为纯文本 JavaScript - typescriptlang.org.

JavaScript 是由ECMA's Technical Committee 39 开发的一种编程语言,ECMA's Technical Committee 39 是由许多不同利益相关者组成的一群人。 TC39 是一个由ECMA 主持的委员会:一个内部标准组织。 JavaScript 由许多不同的供应商(例如 Google、Microsoft、Oracle 等)提供了许多不同的实现。 JavaScript 的目标是成为网络的通用语言。

TypeScript 是 JavaScript 语言的超集,它有一个开源编译器,主要由一个供应商开发:微软。 TypeScript 的目标是通过类型系统帮助及早发现错误并提高 JavaScript 开发效率。

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

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

  2. 高级类型系统 - 类型支持不是 ECMAScript 标准的一部分,并且很可能永远不会归因于 JavaScript 的解释性质而不是编译性质。 TypeScript 的类型系统非常丰富,包括:接口、枚举、混合类型、泛型、联合/交集类型、访问修饰符等等。 TypeScript 的official website 概述了这些功能。 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 以及更多主机(参见 list)。尽管这些语言可能比 JavaScript 的未来可能会更好,但它们面临着更大的风险,即无法获得足够的采用来保证它们的未来。您可能还很难为其中一些语言找到有经验的开发人员,尽管您会找到的开发人员通常更热情。与 JavaScript 的互操作性也可能涉及更多,因为它们与 JavaScript 的实际情况相去甚远。

TypeScript 介于这两个极端之间,因此可以平衡风险。从任何标准来看,TypeScript 都不是一个冒险的选择。如果您熟悉 JavaScript,则只需很少的努力即可适应,因为它不是一种完全不同的语言,具有出色的 JavaScript 互操作性支持,并且最近被大量采用。

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

JavaScript 是动态类型的。这意味着 JavaScript 不知道变量是什么类型,直到它在运行时实际实例化。这也意味着可能为时已晚。 TypeScript 为 JavaScript 添加了类型支持,并在编译为 JavaScript 期间捕获类型错误。如果您正确地玩牌(您输入代码的严格程度或是否输入代码完全取决于您),则由错误假设某些变量属于某种类型而导致的错误可以完全消除。

TypeScript 通过使用类型推断使打字变得更容易,并且不那么明确。例如:TypeScript 中的var x = "hello"var x : string = "hello" 相同。类型只是从它的使用中推断出来的。即使您没有显式键入类型,它们仍然可以帮助您避免做一些会导致运行时错误的事情。

TypeScript 默认是可选类型的。例如function divideByTwo(x) { return x / 2 } 是 TypeScript 中的一个有效函数,可以使用 any 类型的参数调用它,即使使用字符串调用它显然会导致 runtime 错误。就像你在 JavaScript 中习惯的那样。这是可行的,因为当没有显式分配类型并且无法推断类型时,例如在 divideByTwo 示例中,TypeScript 将隐式分配类型any。这意味着 divideByTwo 函数的类型签名自动变为function divideByTwo(x : any) : any。有一个编译器标志禁止这种行为:--noImplicitAny。启用此标志可为您提供更高程度的安全性,但也意味着您将不得不进行更多输入。

类型具有与之相关的成本。首先,有一个学习曲线,其次,当然,使用适当的严格类型设置代码库也会花费你更多的时间。以我的经验,在您与他人共享的任何严肃代码库中,这些成本是完全值得的。 A Large Scale Study of Programming Languages and Code Quality in 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 Code、WebStorm、Atom 和 Sublime。

严格的空检查

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

启用严格的空检查(--strictNullChecks 编译器标志)后,TypeScript 编译器将不允许将 undefined 分配给变量,除非您明确将其声明为可空类型。例如,let x : number = undefined 将导致编译错误。这完全符合类型理论,因为undefined 不是一个数字。可以将x 定义为numberundefined 的总和类型以更正此问题: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.

在构建过程中,TypeScript 的 2016 年会议联合设计师 Anders Hejlsberg 对该功能进行了详细的解释和演示:video(从 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 的变量存在(参见 this answer)。这可能会使您在调试过程中感到困惑,但如果您了解它或检查 JavaScript 代码,通常不会有问题。应该注意的是,Babel 遇到了完全相同的问题。

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

TypeScript 编译插件可用于WebpackGulpGrunt 以及几乎所有其他 JavaScript 构建工具。 TypeScript 文档有一个关于 integrating with build tools 的部分,涵盖了所有内容。如果您想要更多的构建时间检查,也可以使用linter。还有大量的种子项目可以让你开始使用 TypeScript 并结合一系列其他技术,如 Angular 2、React、Ember、SystemJS、Webpack、Gulp 等。

JavaScript 互操作性

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

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

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

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

老实说,这有点麻烦,这可能是你不选择 TypeScript 的原因之一,而是选择像 Babel 这样根本不需要获取类型定义的东西。另一方面,如果您知道自己在做什么,则可以轻松克服因定义文件不正确或丢失而导致的任何类型的问题。

从 JavaScript 转换为 TypeScript

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

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

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

最大的障碍是学习曲线。我鼓励你先玩一个小项目。看看它是如何工作的,它是如何构建的,它使用了哪些文件,它是如何配置的,它是如何在你的 IDE 中运行的,它是如何构建的,它使用了哪些工具等等。如果你知道的话,将一个大型 JavaScript 代码库转换为 TypeScript 是可行的你在做什么。例如在converting 600k lines to typescript in 72 hours 上阅读此博客)。在开始之前,请确保您对语言有很好的掌握。

采用

TypeScript 是开源的(Apache 2 许可,请参阅GitHub)并由 Microsoft 提供支持。 Anders Hejlsberg,C# 的首席架构师正在领导该项目。这是一个非常活跃的项目; TypeScript 团队在过去几年中发布了许多新功能,并且还计划推出许多很棒的功能(请参阅roadmap)。

关于采用和受欢迎程度的一些事实:

【讨论】:

  • “JavaScript 代码是有效的 TypeScript 代码”——实际上并非总是如此。我的意思是 if(1 === '1') {} 这样的代码会在 TS 中给你一个错误,而在 JS 中不会。但大多数时候,如果 JS 代码写得好,那就是真的。
  • 如果您因为缺少分号而失去了宝贵的生产时间,那么使用 Typescript 写作将是救命稻草。
  • Typings 已被弃用,目前的最佳做法是只使用npm(或yarninstall @types/foo。你能更新你的答案吗?
  • @MaciejBukowski 即使 TypeScript 在这种情况下确实抱怨,你仍然会得到一个有效的 JS 输出(这将是你用 TypeScript 编译/转译的 JS 代码)。所以这是一个“编译错误”,并且 not 无效的 TypeScript。 TypeScript 规范中规定,任何有效的 JS 代码都必须是有效的 TS 代码。
  • @Maciej Bukowski if(1 === '1') {} 不会给你一个错误,但它会通知你你的陈述总是假的(这个条件总是返回'假' 因为类型 '1' 和 '"1"' 没有重叠。)我的意思是,如果 JavaScript 开发人员编写这样的代码,他们应该回归基础,有趣的是我与编写 if 语句之类的高级开发人员一起工作 if( 1+1) 或 if(true) 并且这个人赚了很多钱...
【解决方案2】:

所有浏览器都支持并预编译的 Ecma 脚本 5 (ES5)。 ES6/ES2015 和 ES/2016 今年出现了很多变化,所以要弹出这些变化,TypeScript 应该注意这些变化。

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

• TypeScript 的一大优势是我们在投入生产之前及早发现与 Type 相关的问题。如果有任何类型不匹配,这允许单元测试失败。

【讨论】:

  • 不是每年都这样,伙计!.. 经过很长时间的等待,他们改变了规格
  • @SubhamTripathi 每年都非常。 ES2015、ES2016、ES2017,从现在开始直到语言消亡。在 2015 年之前,不是每年,但现在是。去搜索“TC39流程”了解更多。
【解决方案3】:

我最初在 TypeScript 还在的时候写了这个答案 热门新闻。五年后,这是一个不错的概述,但看看 在下面Lodewijk's answer 以获得更多深度

1000 英尺视图...

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

要了解我的意思,请观看Microsoft's introductory video 的语言。

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

它是开源的,但如果您使用受支持的 IDE,您只能在键入时获得智能 Intellisense。最初,这只是 Microsoft 的 Visual Studio(在 Miguel de Icaza 的博客文章中也有提及)。这些天,other IDEs offer TypeScript support too

还有其他类似的技术吗?

CoffeeScript,但这确实有不同的用途。恕我直言,CoffeeScript 为人类提供了可读性,但 TypeScript 还通过其可选的静态类型为工具 提供了深度可读性(更多评论请参见recent blog post)。还有Dart,但它完全替代了 JavaScript(尽管它是can produce JavaScript code

示例

例如,这里有一些 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 通过源映射提供直接调试支持。有关详细信息,请参阅此 Stack Overflow 问题:Debugging TypeScript code with Visual Studio

想了解更多?

我最初在 TypeScript 还很热门的时候写了这个答案。请查看 Lodewijk's answer 对此问题了解更多最新详情。

【讨论】:

  • WebStorm 现在在 TypeScript 上提供了不错的 IntelliSense,并且是多平台的。
  • @Erwinus:你看到这里的类比了吗?您有时也可以使用 javascript 进行编程,在所有其他情况下使用 typescript:它将帮助您检查类型,将提供一些智能感知。为什么不? ;-)
  • @Erwinus 你在假设 TypeScript 是如何工作的。您可以将纯 JavaScript 编写为 TypeScript,并让编译器只进行编译时类型检查。这样做不会造成性能损失。
  • 不,@Erwinus,该代码是可选的。你可以在 TypeScript 中轻松编写纯 JavaScript 版本。
  • @Erwinus TypeScript 的重点是提供编译时类型检查。如果您看不到其中的价值,那很好。 TypeScript 被称为“你的第一个单元测试”。有很多资源讨论了可选类型检查是否有价值,并且比我们在这里可以做的更详细。我不是想说服你任何事情,只是纠正一个误解。
【解决方案4】:

TypeScript 所做的事情类似于 less 或 sass 对 CSS 所做的事情。它们是它的超级集合,这意味着您编写的每个 JS 代码都是有效的 TypeScript 代码。另外,您可以使用它添加到语言中的其他好东西,并且转译的代码将是有效的 js。你甚至可以设置你想要生成代码的 JS 版本。

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

【讨论】:

  • 最佳 TL;DR 是 TS 的页面:“TypeScript 是 JavaScript 的类型化超集,可编译为纯 JavaScript。”
  • 它并没有回答“我为什么要使用它”。这里的 tl;dr 将是:1)向 JavaScript 添加可选的静态类型。类型可以帮助在编译时捕获错误并更好地记录您的程序。 2)您可以编写new JavaScript(ES6 / ES7 / ESnext)并将其编译回ES5,这是支持旧浏览器所必需的;我已经在tsmean.com/articles/vs/typescript-vs-javascript 为那些对 tl;dr 感兴趣的人进行了详细说明
  • “转译的代码将是有效的 JS”——如果你问我,这就是 TypeScript 的致命弱点。这意味着他们不能为 JS 添加几个非常有用的特性;最值得注意的是 runtime 类型检查。编译器时类型安全只是因为从 I/O 读取的任何运行时数据丢失它,或者任何时候从其他 JS 不安全地调用您的转译代码时,这有点烦人。
【解决方案5】:

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

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

总结:如果按预期使用,Typescript 可以使 JavaScript 编程更可靠、更容易。与完整的 SDLC 相比,它可以显着提高 JavaScript 程序员的工作效率。

【讨论】:

  • 什么是 SDLC? AMD?
  • @Oooogi,SDLC == 软件开发生命周期。 AMD == 异步模块定义。后者是特定于 JavaScript 的,而前者在范围上相当通用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 2017-01-10
相关资源
最近更新 更多