本文首发在我的个人博客:http://muyunyun.cn/posts/66a54fc2/

文中的案例代码已经上传到 TypeScript

TypeScript 并不是一个完全新的语言, 它是 JavaScript 的超集,为 JavaScript 的生态增加了类型机制,并最终将代码编译为纯粹的 JavaScript 代码。

TypeScript 简介

TypeScript 由 Microsoft(算上 Angular 2 的话加上 Google)开发和维护的一种开源编程语言。 它支持 JavaScript 的所有语法和语义,同时通过作为 ECMAScript 的超集来提供一些额外的功能,如类型检测和更丰富的语法。下图显示了 TypeScript 与 ES5,ES2015,ES2016 之间的关系。

使用 TypeScript 的原因

JavaScript 是一门弱类型语言,变量的数据类型具有动态性,只有执行时才能确定变量的类型,这种后知后觉的认错方法会让开发者成为调试大师,但无益于编程能力的提升,还会降低开发效率。TypeScript 的类型机制可以有效杜绝由变量类型引起的误用问题,而且开发者可以控制对类型的监控程度,是严格限制变量类型还是宽松限制变量类型,都取决于开发者的开发需求。添加类型机制之后,副作用主要有两个:增大了开发人员的学习曲线,增加了设定类型的开发时间。总体而言,这些付出相对于代码的健壮性和可维护性,都是值得的。

此外,类型注释是 TypeScript 的内置功能之一,允许文本编辑器和 IDE 可以对我们的代码执行更好的静态分析。 这意味着我们可以通过自动编译工具的帮助,在编写代码时减少错误,从而提高我们的生产力。

对 TypeScript 的简介到此,接下来对其特有的知识点进行简单概括总结,(网上很多教程实际上把 ES6, ES7 的知识点也算进 ts 的知识点了,当然这没错~)

数据类型

String 类型

一个保存字符串的文本,类型声明为 string。可以发现类型声明可大写也可小写,后文同理。

  1. let name: string = 'muyy'
  2. let name2: String = 'muyy'
Boolen 类型

boolean是 true 或 false 的值,所以 let isBool3: boolean = new Boolean(1) 就会编译报错,因为 new Boolean(1) 生成的是一个 Bool 对象。

  1. let isBool1: boolean = false
Number 类型
  1. let number: number = 10;
Array 类型

数组是 Array 类型。然而,因为数组是一个集合,我们还需要指定在数组中的元素的类型。我们通过 Array<type> or type[] 语法为数组内的元素指定类型

  1. let arr:number[] = [1, 2, 3, 4, 5];
  2. let arr2:Array<number> = [1, 2, 3, 4, 5];
  3. let arr3:string[] = ["1","2"];
  4. let arr4:Array<string> = ["1","2"];
Enums 类型

列出所有可用值,一个枚举的默认初始值是0。你可以调整一开始的范围:

  1. enum Role {Employee = 3, Manager, Admin}
  2. let role: Role = Role.Employee
  3. console.log(role) // 3
Any 类型

any 是默认的类型,其类型的变量允许任何类型的值:

  1. let notSure:any = 10;
  2. let notSure2:any[] = [1,"2",false];
Void 类型

JavaScript 没有空值 Void 的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数:

  1. function alertName(): void {
  2. console.log('My name is muyy')
  3. }

函数

为函数定义类型

我们可以给每个参数添加类型之后再为函数本身添加返回值类型。 TypeScript能够根据返回语句自动推断出返回值类型,因此我们通常省略它。下面函数 add, add2, add3 的效果是一样的,其中是 add3 函数是函数完整类型。

  1. function add(x: string, y: string): string{
  2. return "Hello TypeScript";
  3. }
  4. let add2 = function(x: string, y: string): string{
  5. return "Hello TypeScript";
  6. }
  7. let add3: (x: string, y: string) => string = function(x: string, y: string): string{
  8. return "Hello TypeScript";
  9. }
可选参数和默认参数

JavaScript 里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是 undefined 。 在 TypeScript 里我们可以在参数名旁使用?实现可选参数的功能。 比如,我们想让 lastname 是可选的:

  1. function buildName(firstName: string, lastname?: string){
  2. console.log(lastname ? firstName + "" + lastname : firstName)
  3. }
  4. let res1 = buildName("鸣","人"); // 鸣人
  5. let res2 = buildName("鸣"); // 鸣
  6. let res3 = buildName("鸣", "人", "君"); // Supplied parameters do not match any signature of call target.

如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined 值来获得默认值。 例如,我们重写上例子,让 firstName 是带默认值的参数:

  1. function buildName2(firstName = "鸣", lastName?: string){
  2. console.log(firstName + "" + lastName)
  3. }
  4. let res4 = buildName2("人"); // undefined人
  5. let res5 = buildName2(undefined, "人"); // 鸣人

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。

  1. class Person{
  2. name:string; // 这个是对后文this.name类型的定义
  3. age:number;
  4. constructor(name:string,age:number){
  5. this.name = name;
  6. this.age = age;
  7. }
  8. print(){
  9. return this.name + this.age;
  10. }
  11. }
  12. let person:Person = new Person('muyy',23)
  13. console.log(person.print()) // muyy23

我们在引用任何一个类成员的时候都用了 this。 它表示我们访问的是类的成员。其实这本质上还是 ES6 的知识,只是在 ES6 的基础上多上了对 this 字段和引用参数的类型声明。

继承
  1. class Person{
  2. public name:string; // public、private、static 是 typescript 中的类访问修饰符
  3. age:number;
  4. constructor(name:string,age:number){
  5. this.name = name;
  6. this.age = age;
  7. }
  8. tell(){
  9. console.log(this.name + this.age);
  10. }
  11. }
  12. class Student extends Person{
  13. gender:string;
  14. constructor(gender:string){
  15. super("muyy",23);
  16. this.gender = gender;
  17. }
  18. tell(){
  19. console.log(this.name + this.age + this.gender);
  20. }
  21. }
  22. var student = new Student("male");
  23. student.tell(); // muyy23male

这个例子展示了 TypeScript 中继承的一些特征,可以看到其实也是 ES6 的知识上加上类型声明。不过这里多了一个知识点 —— 公共,私有,以及受保护的修饰符。TypeScript 里,成员默认为 public ;当成员被标记成 private 时,它就不能在声明它的类的外部访问;protected 修饰符与private 修饰符的行为很相似,但有一点不同,protected 成员在派生类中仍然可以访问。

存储器

TypeScript 支持通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

对于存取器有下面几点需要注意的:

首先,存取器要求你将编译器设置为输出 ECMAScript 5 或更高。 不支持降级到 ECMAScript 3。 其次,只带有 get 不带有 set 的存取器自动被推断为 readonly。 这在从代码生成 .d.ts 文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值。

  1. class Hello{
  2. private _name: string;
  3. private _age: number;
  4. get name(): string {
  5. return this._name;
  6. }
  7. set name(value: string) {
  8. this._name = value;
  9. }
  10. get age(): number{
  11. return this._age;
  12. }
  13. set age(age: number) {
  14. if(age>0 && age<100){
  15. console.log("年龄在0-100之间"); // 年龄在0-100之间
  16. return;
  17. }
  18. this._age = age;
  19. }
  20. }
  21. let hello = new Hello();
  22. hello.name = "muyy";
  23. hello.age = 23
  24. console.log(hello.name); // muyy

接口

接口

TypeScript的核心原则之一是对值所具有的结构进行类型检查。在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

  1. interface LabelValue{
  2. label: string;
  3. }
  4. function printLabel(labelObj: LabelValue){
  5. console.log(labelObj.label);
  6. }
  7. let myObj = {
  8. "label":"hello Interface"
  9. };
  10. printLabel(myObj);

LabelledValue 接口就好比一个名字,它代表了有一个 label 属性且类型为 string 的对象。只要传入的对象满足上述必要条件,那么它就是被允许的。

另外,类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。

可选属性

带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个 ? 符号。可选属性的好处之一是可以对可能存在的属性进行预定义,好处之二是可以捕获引用了不存在的属性时的错误。

  1. interface Person{
  2. name?:string;
  3. age?:number;
  4. }
  5. function printInfo(info:Person){
  6. console.log(info);
  7. }
  8. let info = {
  9. "name":"muyy",
  10. "age":23
  11. };
  12. printInfo(info); // {"name": "muyy", "age": 23}
  13. let info2 = {
  14. "name":"muyy"
  15. };
  16. printInfo(info2); // {"name": "muyy"}
函数类型

接口能够描述 JavaScript 中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。定义的函数类型接口就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。定义后完成后,我们可以像使用其它接口一样使用这个函数类型的接口。

  1. interface SearchFunc{
  2. (source: string, subString: string): boolean;
  3. }
  4. let mySearch: SearchFunc;
  5. mySearch = function(source: string,subString: string){
  6. return source.search(subString) !== -1;
  7. };
  8. console.log(mySearch("鸣人","鸣")); // true
  9. console.log(mySearch("鸣人","缨")); // false
可索引类型

与使用接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到”的类型,比如 a[10]ageMap["daniel"]。 可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。 让我们看如下例子:

  1. interface StringArray{
  2. [index: number]: string;
  3. }
  4. let MyArray: StringArray;
  5. MyArray = ["是","云","随","风"];
  6. console.log(MyArray[2]); // 随
类类型

与 C# 或 Java 里接口的基本作用一样,TypeScript 也能够用它来明确的强制一个类去符合某种契约。

我们可以在接口中描述一个方法,在类里实现它,如同下面的 setTime 方法一样:

  1. interface ClockInterface{
  2. currentTime: Date;
  3. setTime(d: Date);
  4. }
  5. class Clock implements ClockInterface{
  6. currentTime: Date;
  7. setTime(d: Date){
  8. this.currentTime = d;
  9. }
  10. constructor(h: number, m: number) {}
  11. }
继承接口

和类一样,接口也可以相互继承。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。

  1. interface Shape{
  2. color: string;
  3. }
  4. interface PenStroke{
  5. penWidth: number;
  6. }
  7. interface Square extends Shape,PenStroke{
  8. sideLength: number;
  9. }
  10. let s = <Square>{};
  11. s.color = "blue";
  12. s.penWidth = 100;
  13. s.sideLength = 10;

模块

TypeScript 与 ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块。

  1. export interface StringValidator{
  2. isAcceptable(s:string): boolean;
  3. }
  4. var strReg = /^[A-Za-z]+$/;
  5. var numReg = /^[0-9]+$/;
  6. export class letterValidator implements StringValidator{
  7. isAcceptable(s:string): boolean{
  8. return strReg.test(s);
  9. }
  10. }
  11. export class zipCode implements StringValidator{
  12. isAcceptable(s: string): boolean{
  13. return s.length == 5 && numReg.test(s);
  14. }
  15. }

泛型

软件工程中,我们不仅要创建一致的定义良好的 API ,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

初探泛型

如下代码,我们给 Hello 函数添加了类型变量 T ,T 帮助我们捕获用户传入的类型(比如:string)。我们把这个版本的 Hello 函数叫做泛型,因为它可以适用于多个类型。 代码中 outputoutput2 是效果是相同的,第二种方法更加普遍,利用了类型推论 —— 即编译器会根据传入的参数自动地帮助我们确定T的类型:

  1. function Hello<T>(arg:T):T{
  2. return arg;
  3. }
  4. let outPut = Hello<string>('Hello Generic');
  5. let output2 = Hello('Hello Generic')
  6. console.log(outPut);
  7. console.log(outPut2);

参考资料

从 JavaScript 到 TypeScript的更多相关文章

  1. 从 JavaScript 到 TypeScript 系列

    随着应用的庞大,项目中 JavaScript 的代码也会越来越臃肿,这时候许多 JavaScript 的语言弊端就会愈发明显,而 TypeScript 的出现,就是着力于解决 JavaScript 语 ...

  2. JavaScript 和 TypeScript 交叉口 —— 类型定义文件(*.d.ts)

    在 <从 JavaScript 到 TypeScript 系列> 文章我们已经学习了 TypeScript 相关的知识. TypeScript 的核心在于静态类型,我们在编写 TS 的时候 ...

  3. JavaScript 和 TypeScript 中的 class

    对于一个前端开发者来说,很少用到 class ,因为在 JavaScript 中更多的是 函数式 编程,抬手就是一个 function,几乎不见 class 或 new 的踪影.所以 设计模式 也是大 ...

  4. JavaScript、TypeScript、ES6三者之间的联系和区别

    ES6是什么 ECMAScript 6.0(以下简称ES6)是JavaScript语言(现在是遵循ES5标准)的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以 ...

  5. JavaScript和TypeScript的区别和联系

    转载自:http://web.jobbole.com/93618/?utm_source=group.jobbole.com&utm_medium=relatedArticles JavaSc ...

  6. Web Essentials之JavaScript,TypeScript和CoffeeScript

    返回Web Essentials功能目录 一些Javascript功能也可以用于TypeScript. 本篇目录 功能 智能提示 TypeScript CoffeeScript 功能 JSHint J ...

  7. typedi 强大的javascript以及typescript 依赖注入框架

    typedi 是typestack团队提供的依赖注入解决方案,对于typescript 我们可以使用注解的开发方式,官方的文档也比较详细 javascript 使用 基于函数的服务注入 var Ser ...

  8. JavaScript 、TypeScript 中的 Boolean

    boolean 是 JavaScript 中一种有趣的原始数据类型.在TypeScript中,非严格模式下("strictNullChecks": false),它总共允许4个值 ...

  9. Javascript和Typescript语言类型

    静态语言(强类型语言) 静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型. 例如:C++.Java.Delphi.C#等. 动态语言(弱类型语言) 动 ...

随机推荐

  1. 【JAVAWEB学习笔记】04_JavaScript

    晨读单词: onmouseover:鼠标移入 onmouseout:鼠标移出 attribute:属性 node:节点 document:文档 element:元素 textNode:文本节点 app ...

  2. 在 eclipse 中将 web 项目部署到 tomcat 服务器上

    1.在 eclipse 中,选择 Window--->Preferences--->Server--->Runtime Environments,选择 Add 按钮 2.在弹出的对话 ...

  3. XSS研究1-来自外部的XSS攻击

    引入: 上文中我们的例子是研究了来自内部的XSS攻击,通过输送一段有害js代码到受害者的机器,让其在受害者的域上运行这段有害JS代码来得到入侵目的.现在我们来看下来自外部的XSS攻击. 实践: 下面还 ...

  4. 028hibernate缓存(性能优化策略)

    一级缓存 二级缓存 查询缓存 缓存是为了提高性能 变化不是很大,相对静态的对象放入缓存 对象的创建比较耗时

  5. python的列表(二)

    1.遍历整个列表  #for 循环 # >>> name_list['faker', 'dopa', 'gogoing', 'uzi']  >>> for LOL_ ...

  6. HTML中部分标签的嵌套问题

    书写HTML结构的时候,对于标签的嵌套问题,在我发现这个问题之前,都不在自己的考虑之中,还傻傻的以为标签之间是可以进行百搭的! 其实,有些标签是不能进行随意嵌套,如果你没有深受其害,你是不会发现它的存 ...

  7. Windows下以Local模式调试SparkStreaming的WordCount例子

    1.下载Windows版的NetCat https://eternallybored.org/misc/netcat/ 2.启动NetCat nc -l -p 9999 3.将SAPRK_HOME\c ...

  8. webpack务虚扫盲

    打包工具的角色 所谓打包工具在web开发中主要解决的问题是: (1)文件依赖管理.毕竟现在都是模块化开发,打包工具首先就是要梳理文件之间的依赖关系. (2)资源加载管理.web本质就是html.js和 ...

  9. Wampserver红色橙色解决思路----端口冲突是关键

    Wampserver不是绿色:wampserver下载安装不需要配置环境,在这之前需要下载tomcat,并确保启动,不然会是红色.安装好wampserver(就是在安装过程不会弹出缺少什么文件,我的就 ...

  10. 跟着刚哥深入学maven

    前言:目前所有的项目都在使用maven,可是一直没有时间去整理学习,这两天正好有时间,好好的整理一下. 一.为什么使用Maven这样的构建工具[why] ① 一个项目就是一个工程 如果项目非常庞大,就 ...