转职成为TypeScript程序员的参考手册

写在前面

做者并无任何能够做为背书的履从来证实本身写做这份手册的份量。 html

其内容大都来自于TypeScript官方资料或者搜索引擎得到,期间掺杂少许做者的私见,并会标明。 html5

大部份内容来自于http://www.infoq.com/minibooks/typescript-c-sharp-programmers java

你甚至能够认为这就是对这本英文小册子的翻译,实际上80%如此。 git

写给那些已经有编程基础,尤为是掌握c语言、c#、java这一类型的静态类型语言的同好。 程序员

鸣谢

先谢国家,虽然并不知道要谢些什么。 github

感谢个人太太和个人猫,他们的陪伴让我沉溺于电脑世界却不孤独。 web

感谢那些上班时间奋战在QQ群里的程序斗士们,他们让我始终秉持一颗艺术家的心。 typescript

感谢微软,TypeScript是微软的注册商标哦。 编程

真正的开篇文字

只要你是对html5这个话题感兴趣的程序员,咱们就离不开JavaScript这个话题。而新兴的TypeScript想必你也会有极大的兴趣。JavaScript现在处处都是,web、服务器(经过NodeJS)、移动应用(经过各类框架),全部这些,TypeScript均可以使用,而且能够为JavaScript扩展出面向对象和静态类型的特征。 c#

TypeScript最初的灵感来自ECMAScript6,也就是将来的JavaScript。

TypeScript能让咱们提早使用将来的语言特性,甚至更多,例如泛型这种语言特性。

TypeScript代码,最终会编译为地道的JavaScript,兼容一切使用JavaScript的场合。

编译过程主要是编译时检查,一点改写,删除类型批注和接口。删除类型批注和接口这个过程称为类型擦除(Type Erasure)。

我从网上找到一张很好的图片用来讲明类型擦除,以下。

TypeScript的创造者是微软的一个开发团队,该团队的领导者是C#之父 和 Delphi之父,Anders Hejlsberg。

2012年10月1日发布,彻底开源。

当前版本已达1.8,已经拥有了不少生产力项目,TypeScript的主页在http://www.typescriptlang.org/

咱们后面将详细介绍TypeScript并对比他和其余语言的异同,主要是C#。

关于TypeScript究竟是Compiling 仍是 Transpiling

这个话题很难说清楚,可是颇有必要在提到TypeScript的时候讲一下,这两个词:编译Compiling,Transpiling有人译做转译,这是一个英文计算机术语。通常认为转译是一种特殊的编译,当将一种源代码语言编译成另一种源代码语言时,就称为转译。

当编译一个c#程序时,是由源代码语言C#编译为IL,这就不能称为Transpiling,由于他们是彻底不一样的东西。

而编译TypeScript程序时,他变成了另一种源代码JavaScript,这个就称为Transpiling(转译)。

但不管如何,Transpiling是Compiling的特例,Transpiling也属于Compiling。

因此TypeScript转译为Javascript,TypeScript编译为JavaScript,都是没有问题的讲法。

 

TypeScript语言特性

这里快速介绍一下TypeScript的关键语法,好比显示类型批注、类、接口。

虽然C# Java程序员都很熟悉面向对象,但TypeScript并不基于C#,因此仍是有所区别的。

TypeScript是静态类型语言,须要编译,拥有编译时类型检查的特性。

编译时类型检查可以确保类型安全,并方便开发更智能的自动完成功能,实际上TypeScript的各类开发工具都作得很不错。

好比VisualStudio,编写TypeScript文件时,就比编写JavaScript要聪明的多。这就是静态类型带来的好处。

TypeScript文件

TypeScript文件的扩展名为".ts",你可使用不少工具编写.ts文件,好比visualstudio。更多信息,请看官网http://www.typescriptlang.org/

 

官网还提供了一个在线编写测试.ts文件的环境http://www.typescriptlang.org/Playground/

一个TypeScript应用包含多个TypeScript代码文件,一个代码文件能够包含多个ClassClass也能够组成模块。

模块的概念和C#中组织类型的namespace比较接近。

运行时,TypeScript编译获得的JavaScript能够经过Html标签<Script>加入网页中,也可使用其余的模块加载工具,好比NodeJS就内置了模块加载工具。

不使用模块组织依赖的时候,一个TypeScript文件依赖另外一个TypeScript文件,应该加上引用注释

(这是可选的,通常也不使用命令行编译,大部分图形化工具不加也能够)。

当使用模块加载工具的时候(好比RequireJS,或者NodeJS内置加载工具),代码以下:

不知道啥时RequireJS的同窗请自行补课。

 

当你使用import语句的时候,是有两种模式的,CommonJS AMD模式,他们编译为JavaScript生成的代码不一样,这个根据你使用不一样的加载工具请本身设置TypeScript编译选项。

 

注:RequireJS使用CommonJS模式,NodeJS使用AMD模式。

 

类型

TypeScript的基本类型有 string,number,boolean,null 和undefined.

由于JavaScript没有整数小数这些区分,因此TypeScript也没有添加,统一使用number。

另外TypeScript添加了一个any类型,当须要动态类型时使用。这个与C#的动态关键字是相似的。

TypeScript支持数组类型,经过在类型后面添加方括号定义,好比string[].

也能够自定义类型,在讲到class的时候咱们细说。

类型推断

当右侧表达式足以肯定变量的类型时,TypeScript能够自动肯定变量的类型,这个特性C#也有。

好比这个代码

若是在VisualStudio中,鼠标悬停,依然能够看到这三个变量被识别出来是各自不一样的类型。

 

类型推断还能处理更复杂的类型信息,好比这个代码,无需类型标注便可得到静态类型的好处。

写完这个代码之后,以后再键入example,再敲入.,也能够得到自动完成提示,.name,.id.collection.

类型推断始终是有局限性的,基本上是依靠右侧表达式来推断。若是声明变量时没有推断出来,过后赋值也推断不出来了。

好比下面的代码。

当声明变量时没法推断出,变量即被标注为 any 类型,any类型彻底没有任何类型安全方面的保证。固然自动完成功能也没有。

类型批注

TypeScript的类型是设计为批注,而不是定义,是可选的,因此和C#的类型写在前面不一样,类型是以可选的形式写在后面的。

咱们将上面的全部代码都加上类型标注

这些标注的添加和上面自动类型推断的结果是同样的。可是阅读代码的人就能够一眼看出。

模块、类型、接口

TypeScript的模块用于代码组织,相似C#的namespace。一个模块能够包含多个类和接口。能够将类和接口私有化或者导出,导出的意思就是公开,让其余模块能够访问他们。

TypeScript的class和C#的class意义相同。实际上TypeScript的一个亮点就是他隐藏了JavaScript的原型设计,而是采用了更流行的基于类型的面向对象方式。你能够扩展其余的class,实现多个接口,添加构造函数,公开属性和方法。这些都和c#的class很类似。

属性和方法可使用public 或private访问修饰符 修饰。当在构造函数的参数上使用访问修饰符的时候,他们会自动为该类型添加同名的属性。请很是当心这个语法,这和不少语言都不一样

如图中Point的构造函数参数x,y 使用了public 访问修饰符,因此会自动生成Point的成员变量x和y,这是TypeScript的特有语法。

图中的export 关键字使类和接口在模块外部可见。实现接口使用implements关键字,继承类使用extends关键字,这点和C#直接用一个冒号表达不一样。

当你扩展一个类时,用super关键字调用基类的方法。用this关键字来调用当前类的属性和方法。重写基类的方法是可选的。构造函数必需要调用基类的构造函数,编译器会提醒你的。

模块名称包含点,一个模块能够定义在多个文件中。模块的名字别太长,访问的时候打字会比较累。下图是一个比较累的例子

函数(或者叫功能)的参数

TypeScript的函数参数拥有丰富的特性:可选参数、默认参数、不定参数。

有一些和其余语言的设计不太相同。下面将一一说明。

虽然在设计上,这些参数特性都不是必要的,可是TypeScript的这些地方都有些特殊性,你得了解一下,以备看懂。

可选参数的设计和C#基本一致,符号用? 表示可选参数,可选参数必须出如今必选参数以后。

默认参数只要在定义时给附上值就好了,而且和c#不一样,TypeScript的默认参数不须要是常量,运行时可解释便可,后文会有说明

下图是特殊的默认参数

不定参数能够指定任意数量,能够为零,这个设计也和c#相似,只是要添加三个点。

下面就是不定参数的一个典型使用场景

函数重载

Javascript是不容许重名函数的,TypeScript实现的重载和c#有很大的不一样。

TypeScript的重载是要把全部的函数签名写出来,写一份实现,而且最后一个函数签名要能包含上面全部的函数签名。

以下图:

和C#三个重载的函数就拥有三个函数体不一样,TypeScript的重载其实全是 overloadedMethod(input:any)这最后一个签名的实现,上面的两个只是两个兼容的签名。可是配合可选参数仍是可以表现出和c#的函数重载相似的调用方式。函数编写方式免不了要写不少的if了。

枚举

TypeScript的枚举很是相似C#,你能够指定值。

也能够反过来经过枚举值取到枚举的名字

这里面的细节就再也不赘述了,你能够观察枚举编译为JavaScript之后是什么样子

泛型

对c#程序员来讲,TypeScript的泛型很熟悉,基本上是一致的设计。

类型约束

C#使用where关键字标记类型约束,TypeScript在尖括号内使用extends关键字,效果相同。

下面的例子中IExample约束了泛型必须是IMyInterface和他的派生类。

若是像下图这样用的话,就能约束为同时继承ClassOne和ClassTwo的类型。很费解吧,请特别注意

这是由于本质上TypeScript的类型系统并不那么严格,下面的章节会详细解释TypeScript的类型系统

你也可使用泛型做为泛型的类型约束,以下

结构类型

C#的类型系统是强制标记的,对象的类型必须显示声明。即便两个类型拥有彻底相同的结构,他们也不是相同的类型。

TypeScript的类型系统是结构上的,建筑结构,层次型的。结构相同的类型便可认为是同一类型。

下面是C#中的一个例子

ClassA ClassB是彻底不一样的类型,他们之间是不一样的,必须显示继承接口才能让他们兼容。

而在TypeScript中不是这样,咱们用以下的例子来证实。ClassA ClassB ExampleC 拥有签名一致的函数,因此他们就能够兼容。

TypeScript的结构类型系统意味着你在c#中的观念再也不成立,class name不是关键。这须要咱们写代码的时候时刻注意。

这玩意会让代码变幻无穷,若是你熟悉C#或者JAVA,这可能会让你困惑。

 

看下面的例子,不须要class关键字,也会实实在在的产生类型。

在这个例子中,会产生一个匿名的类型

这个匿名的类型可让开发工具提供自动完成功能,编译器也会检查。若是你尝试将objA的name赋值一个数值,编译器会检查到告诉你错误。编译器还会为数组推断类型。

访问修饰器

TypeScript的访问修饰器可能会给你一种弱小的感受,的确如此。他仅仅是一个编译时功能。

模块中的一切均为私有,除非加上export关键字。没有export关键字的类型仅能在模块内实用。

类的内部,一切均为公开,除非加上private 关键字。public只是为了看起来意图明确。

TypeScript的访问修饰器就是这样而已,没有c#的 internal 和 protected这种修饰器,想要c#相似的功能就放弃吧。

TypeScript特性

内存管理

当你运行TypeScript 程序时,他会被编译为JavaScript程序来运行。JavaScript的内存管理和C#比较接近。内存在对象建立时分配,在对象再也不使用时回收。不一样的是垃圾回收机制在JavaScript的世界里没有标准统一的实现,这意味着你的JavaScript程序的内存性能相比C#难以预测。

好比说,在比较早的浏览器上,可能使用的是引用计数垃圾回收机制,当一个对象的引用计数达到0时,将回收内存。这种垃圾回收机制比较快速和即时。可是当发生循环引用时,引用计数将永远也没法达到零。

比较新的浏览器使用标记与清扫垃圾回收机制来找出不可访问到的对象,很大程度上避免了这个问题。这种垃圾回收机制比较缓慢,但他能避免循环引用致使的内存泄露。

关于两种垃圾回收机制有不少的资料能够研究,这里只是想告诉你,别相信你的直觉,浏览器会很不一样。

资源释放

在TypeScript中,一般都不会使用到非托管的资源,Node.JS中多一点。大部分浏览器将底层交互API设计为回调控制,不向你暴露对象,不须要你本身管理非托管资源。好比下面接近传感器的API使用方法。

如你所见,使用回调并不须要管理任何引用。Node.js中有时会碰到须要本身释放的对象,你要保证释放这些对象,不然就会内存泄露。你可使用 try finally 块,释放代码写在 finally 块中。这样就能保证就算发生任何错误,释放代码都会执行。

异常

在TypeScript中,你能够用throw关键字引起一个异常。

在JavaScript中,throw能够throw任何类型的东西。可是再TypeScript中,throw的必须是一个Error对象。

要自定义异常,能够继承Error类。当你须要一个特定的异常行为或者你但愿catch块能够分辨异常类型时,自定义异常就会颇有用。

处理异常须要使用try catch语句块。大致上和c#的使用方法是很接近的,可是c#支持多个catch块,TpyeScript不能够,你能够用error.name来区分异常类型。

若是须要一些即便发生异常也会调用的代码,你就须要finally语句块了,他们的执行顺序以下图

数组

TypeScript 从0.9开始,数组就是能够指定内容的准确类型。用法是,用类型批注加上方括号。TypeScript会检查加入到数组中的条目的类型,也会推断从数组中检索的条目的类型。

由于TypeScript没有本身的框架库,因此只能使用内置的JavaScript函数和浏览器接口,没有像C#的List<T> 这样的泛型库。但这并不能阻止咱们本身创造一个。下面是一个泛型列表类的例子,只是个演示。

 

上面这个List类演示了许多TypeScript的语言特性和使用方法,就像C#的List<T>那样。下面是如何使用这个List类的例子。

日期与时间

TypeScript中的Date对象是基于JavaScript Date 对象的,他是由从1970年零点 utc时间开始的毫秒数。

Date对象可以接受各类精度的初始化,以下。

你也可使用RFC和ISO格式的字符串初始化Date对象,固然,毫秒数也能够(从1970年1月1日开始)。

请注意,这不是时间戳,时间戳单位是秒,数字比这个少几个零。

Now

你能够访问如今的日期与时间,经过方法Date.Now();返回值是毫秒,你若是须要用Date对象去操做。须要用这个值去初始化一个Date对象

Date 的方法

当你有一个Date对象时,你能够用内部方法获取日期的一部分。有两套方法,一套本地,一套UTC。在下面的实例中,你看到咱们把getUTCMonth的值加了1.由于返回值从零开始,因此一月是 02 月是 1,等等。

日期的各个部分为年、月、日、小时、分钟、秒、毫秒。全部这些值均可以在获取本地的和 UTC 的。还能够用 getDay getUTCDay获得星期,从零开始,星期天为 0,星期一为1

 

也能够利用各类格式显示日期。以下。

事件

TypeScript中的事件是 DOM API(Document Object Model),DOM API事件是一套标准的鼠标和键盘交互和对象和窗体事件。下面的事件列表并不是详尽无遗。

鼠标事件

事件

触发时机

onblur

焦点离开目标组件

onclick

目标组件检测到鼠标单击

ondblclick

目标组件检测到鼠标双击

onfocus

目标组件得到焦点

onmousedown

目标组件检测到鼠标按下

onmousemove

目标组件检测到鼠标指针移动

onmouseover

鼠标指针通过目标组件

onmouseout

鼠标指针离开目标组件

onmouseup

目标组件检测到鼠标按钮松开

 

键盘事件

事件

触发时机

onkeydown

目标组件键盘按下

onkeypress

目标组件键盘按键按下并松开

onkeyup

目标组件键盘松开

对象事件

事件

触发时机

onload

对象加载(文档或图像等)

onresize

对象尺寸改变

onscroll

一个文档滚动

onunload

文档关闭

表单事件

事件

触发时机

onchange

目标输入框的内容改变

onreset

表单重置(清空)

onsubmit

表单提交

自定义事件

TypeScript中自定义事件和DOM内置事件采用相同的机制发布和侦听。任何事件均可以有多个侦听器和多个发布者。下面是一个侦听自定义事件的例子

 

下面的类发布自定义的事件:

执行顺序

事件按照他们被注册的顺序执行。这个因素很重要,由于事件处理程序是序列执行,不是同时,顺序会影响逻辑。

当你注册两个事件侦听器,而且第一个执行了5秒钟。那么第二个就不会执行,一直要等到第一个执行完毕以后才会被执行。若是第一个侦听器出错,第二个仍是会执行。

你能够用setTimeOut时间参数为零的方式去执行你的长时间操做,这至关于多线程,就不会堵住其余的事件执行了。

框架

TypeScript捆绑了那些经常使用对象和方法。由于Web标准在不断的演变,你可能会常常发现一些新的东西尚未被包含在标准库中。你能够查看你计算机上的TypeScript标准库文件,他在SDK目录中,一般多是:

C:\Program Files (86) \Microsoft SDKs\TypeScript\lib.d.ts

你永远也不该该修改这个文件,若是你须要新的定义,咱们能够继续增长新的定义文件。

下面的是 ClientRectList TypeScript库文件中的当前定义。

若是要为 ClientRectList添加一个新的isOrdered属性,只需简单的在你本身的程序中添加如下接口扩展程序,便可当即使用。

当它被添加到标准库时,你本身的扩展会引起一个生成错误,到时把它删除了就好了。

当你建立ClientRectList的实例时,你将可以访问过去的方法,以及获取新的 isOrdered 属性。

除了这些TypeScript标准库的定义,TypeScript没有捆绑任何其余的框架。在前一章中,咱们谈到了,你能够重建你的各类功能,好比像C#同样,由于TypeScript有着丰富的语言功能。你也能够访问全部现有的 JavaScript 框架,jQueryKnockoutAngular和其余数以百计的框架。可是他们都用纯 JavaScript开发,你不会获得加强的开发体验,除非,你有一个匹配的定义文件。幸运的是,有一个项目,他们致力于为全部的JavaScript框架提供TypeScript定义。Definitely Typed 项目,Github地址是:

https://github.com/borisyankov/DefinitelyTyped

建立定义

有时你会想使用JavaScript的库、框架或者工具集。TypeScript编译器难以理解这些外部的代码,由于他们没有类型信息。

动态定义

在程序中使用外部代码的最简单方法是声明一个any变量。TypeScript编译器容许any对象调用任何方法于属性。这会让你经过编译,可是没有自动完成和类型检查。

在此示例中的特殊关键字是declare。这会告诉编译器,这个变量是外部的,这个仅仅是编译时的关键字,编译为JavaScript时会被擦除。

类型定义

为了使用外部JS代码能获取更佳的开发体验,你须要提供更全面的定义。能够声明变量、 模块、 类和函数,定义外部代码的类型信息。Declare关键字仅仅须要在定义的开头使用一次。

 

若是但愿外部代码能够由TypeScript扩展,定义为class,不然,定义为interface

这两种定义方法的惟一区别是可否继承扩展。这两种状况下,类型信息都仅为编译时使用,编译为JavaScript后都会进行类型擦除。

不少时候,定义会组成一系列接口,组合成很大的一幅图景。你甚至能够为TypeScript不能实现的JavaScript方法建立定义。

例如,它是以下图这样作:

在此示例中有一个名为move的难以想象的属性,他能够做为函数使用。这样一来,咱们就能够声明几乎任何的JavaScript代码, jQueryKnockoutAngularRequireJS 和其余的老的JavaScript代码,让你能在TypeScript中使用它们而没必要重写。

一些有用的小技巧

获取运行时类型

若是在运行时,想要获得类的名称,在C#中有反射这种方法,但TypeScript没有明显的内置方法。

静态方法 getType,检查编译后的 JavaScript 函数,而后提取它的名字,这就是TypeScript中的类的名称。

这种技术的限制是你不能得到包含类和模块的完整名称,这意味着:

MyModule.Example SomeOtherModule.Example 和没包装的叫作Example的类,它们全部的返回字符串均为Example

 

扩展原生对象

TypeScript内置的定义文件描述了JavaScript原生对象和函数。你能够在lib.d.ts库文件中查看它们。你会注意到大部分都是使用interface定义的,不但愿你继承它们。但咱们仍是能够扩展它们的。

例如,下面是给NodeList对象增长onclick事件。


可是这个代码会被TypeScript编译器警告,告诉你,NodeList对象没有onclick函数。

为了解决此为题,你须要在你本身的代码中添加定义代码。

这个接口声明能够写在任何引用的ts文件中。

 

相关文章
相关标签/搜索