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

IT技术 javascript typescript
2021-01-20 14:56:00

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

它可以做什么 JavaScript 或可用库不能做的事情,让我有理由考虑它?

5个回答

我最初在 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()方法返回一个字符串。

调试typescript

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

想知道更多?

我最初在 TypeScript 仍然很火的时候写了这个答案。查看Lodewijk对此问题的回答,了解更多最新细节。

@Erwinus TypeScript 的重点是提供编译时类型检查。如果你没有看到其中的value,那完全没问题。TypeScript 被称为“你的第一个单元测试”。有很多资源讨论了可选类型检查是否有value,而且比我们在这里可以做的更详细。我不是要说服你什么,只是纠正一个误解。
2021-03-13 14:56:00
不,@Erwinus,该代码是可选的。您可以轻松地在 TypeScript 中编写纯 JavaScript 版本。
2021-03-23 14:56:00
WebStorm 现在在 TypeScript 上提供了很好的 IntelliSense,并且是多平台的。
2021-03-26 14:56:00
@Erwinus:你在这里看到类比了吗?您有时也可以使用 javascript 进行编程,在所有其他情况下使用typescript:它将帮助您检查类型,将提供一些智能感知。为什么不?;-)
2021-04-03 14:56:00
@Erwinus 您正在对 TypeScript 的工作方式做出假设。您可以将纯 JavaScript 编写为 TypeScript,并让编译器只进行编译时类型检查。这样做不会有性能损失。
2021-04-05 14:56:00

TypeScript 与 JavaScript 的关系

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

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

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

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

  1. 支持现代 JavaScript 功能- JavaScript 语言(而非运行时)通过ECMAScript标准进行标准化。并非所有浏览器和 JavaScript 运行时都支持所有 ECMAScript 标准的所有功能(请参阅此概述)。TypeScript 允许使用许多最新的 ECMAScript 功能,并将它们转换为您选择的旧 ECMAScript 目标(请参阅编译--target器选项下的编译目标列表)。这意味着您可以安全地使用新功能,如module、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 添加了类型支持,并在编译为 JavaScript 期间捕获类型错误。如果您正确地打牌(您键入代码的严格程度或是否键入代码取决于您),则可以完全消除由某些变量属于某种类型的错误假设引起的错误。

通过使用类型推断,TypeScript 使打字变得更容易,也更不明确。例如:var x = "hello"在 TypeScript 中与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 的巨大改进。TypeScript 编译器会实时通知 IDE 其丰富的类型信息。这提供了几个主要优点。例如,使用 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,您可以通过使用不可为 null 的类型来消除这些类型的错误。其工作原理如下:

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

一旦已知一个类型可以为 null,这意味着它的类型也可以是 valuenullundefined,TypeScript 编译器可以通过基于控制流的类型分析来确定您的代码是否可以安全地使用变量。换句话说,当您undefined通过例如一条if语句检查变量时,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 对该功能进行了详细的解释和演示:视频(从 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 代码,这通常不是问题。应该注意的是,Babel 遇到了完全相同的问题。

TypeScript 编译器还有一些其他技巧可以做,比如基于装饰器生成拦截代码,为不同的module系统生成module加载代码和解析JSX但是,除了 Typescript 编译器之外,您可能还需要一个构建工具。例如,如果您想压缩代码,则必须向构建过程添加其他工具才能这样做。

有适用于WebpackGulpGrunt和几乎所有其他 JavaScript 构建工具的TypeScript 编译插件TypeScript 文档中有一个部分是关于涵盖所有这些的构建工具集成的部分一个棉短绒也可如果你想更多的编译时间检查。还有大量的种子项目可以让你开始使用 TypeScript,结合其他一些技术,如 Angular 2、React、Ember、SystemJS、Webpack、Gulp 等。

JavaScript 互操作性

由于 TypeScript 与 JavaScript 密切相关,因此它具有强大的互操作能力,但需要一些额外的工作才能在 TypeScript 中使用 JavaScript 库。typescript定义需要这样的typescript编译理解函数调用像_.groupBy或者angular.copy或者$.fadeOut不是真正意义上的非法语句。这些函数的定义放在.d.ts文件中。

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

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

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

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

从 JavaScript 转换为 TypeScript

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

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

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

最大的障碍是学习曲线。我鼓励你首先尝试一个小项目。看看它是如何工作的,它是如何构建的,它使用哪些文件,它是如何配置的,它如何在你的 IDE 中运行,它是如何构建的,它使用哪些工具等等。当你知道将一个大型 JavaScript 代码库转换为 TypeScript 是可行的你在做什么。阅读此博客,例如在 72 小时内将 60 万行转换为typescript)。在进行跳转之前,请确保您对语言有很好的掌握。

采用

TypeScript 是开源的(Apache 2 许可,请参阅GitHub)并由 Microsoft 提供支持。C# 的首席架构师Anders Hejlsberg是该项目的带头人。这是一个非常活跃的项目;在过去的几年里,TypeScript 团队已经发布了很多新功能,并且仍然计划推出很多很棒的功能(请参阅路线图)。

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

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

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

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

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

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

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

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

什么是 SDLC?超微?
2021-03-23 14:56:00
@Oooogi,SDLC == 软件开发生命周期。AMD == 异步module定义。后者特定于 JavaScript,而前者在范围上相当通用。
2021-03-24 14:56:00

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

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

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

@SubhamTripathi它很逐年递增。ES2015、ES2016、ES2017,从现在开始直到该语言消亡。不是每一年,在2015年之前,但它现在是。去搜索“TC39 进程”以了解更多信息。
2021-03-11 14:56:00
这不是每年的哥们!..他们在漫长的等待后改变了规格
2021-03-15 14:56:00