TypeScript
安装TypeScript
初始TypeScript
TypeScript的设计目标是开发大型应用。它可以编译成纯JavaScript,编译出来的JavaScript可以运行在任何浏览器上(说明兼容性特别好)。
TypeScript支持 类型定义、类、接口、枚举、泛型等特性。
TypeScript是 JavaScript类型的超集,简称TS。包含JavaScript语法,支持ES6标准。
安装TypeScript
打开cmd命令提示符窗口,输入命令:
npm install -g typescript
检测是否安装成功,输入命令:
tsc -v
数据类型与推断
数据类型
基本数据类型
string、number、boolean、 null、undefined、symbol
引用类型
array、object、Function、any(表示任意类型,即没有固定类型)
空值
void(表示变量,也可以表示函数返回值。)
创建 ts文件
1、hello.ts代码如下

let hello:string="hello YAP"; hello="hello DJQ"; let message:any="我是任意类型"; message=20; console.log(hello); console.log(message);
编译 ts 文件
方法1
在项目目录的终端下,输入以下命令 ,编译ts文件:
tsc ./1、hello.ts //编译成功,多出一个 1、hello.js 文件,然后就可以在相关的 html文件中引用该 js文件,再运行该 html文件。
//或者直接在终端输入 node 1、hello.js ,运行 该js文件。
方法2
全局安装 ts-node模块
打开cmd命令窗口,输入命令
npm install -g ts-node
直接访问ts文件进行测试
直接运行ts文件,输入命令
ts-node 1、hello.ts
npm install -D tslib @types/node
接口与联合类型
联合类型 |
表示取值可为多种类型之一。
可以通过管道 (|),将变量设置为多种类型。赋值时,可以根据设置的类型来赋值。

let muchType:string|number="hello";
muchType=20;
接口
可以理解为一种类型,一个规范,一个约束。可以对数组、对象、类进行约束。
接口中可定义 可选属性、只读属性、任意属性。这样在开发代码时便于调试。

interface Istate{ name:string; age:number; } let user:Istate={name:'YAP',age:25}; //接口的值必须是一个对象。
支持 可选属性 ?

interface Istate{ name:string; age?:number; //?表示可选属性。即可有可无。 } let user:Istate; user={name:'YAP',age:25}; user={name:'DJQ'};
支持 只读属性 readonly

interface Istate{ name:string; readonly age:number; //readonly表示只读属性 } let user:Istate; user={name:'YAP',age:25}; //user.age=20; 报错。只能初始化时被赋值。后面不能更改。
支持 联合类型 |

interface Istate{ name:string; age:number|string; //|表示联合类型 } let user:Istate; user={name:'YAP',age:25}; user={name:'DJQ',age:'25'};
对象属性个数不确定 [propName:string]:any

interface Istate{ name:string; age:number|string; [propName:string]:any; //动态添加属性 propName自定义 } let user:Istate; user={name:'YAP',age:25}; user={name:'DJQ',age:'25',address:'广州',job:"saler"};
约束数组 [index:number]:any

interface IArray{ [index:number]:number|string; //约束数组 index自定义,[]中的number代表数组索引类型 } let array:IArray=[1,2,3,1,"yap"];
数组与元组
联合类型也可以在数组和元组的定义中使用。
数组
数组对象,是使用单独的变量名,来存储一系列的值。
两种定义方式。
类型+方括号 来定义

let arr:number []=[1,2,3]; let arr2:string []=["1","2","3"]; let arr3:any []=[1,"2",true];
数组泛型 来定义

let arrType:Array<number>=[1,2,3]; let arrType2:Array<string>=["1","2","3"]; let arrType3:Array<any>=[1,"2",true];
元组
表示把数组的格式都定义好了。

let arr4:[number,string,boolean]=[1,"大家好",true]; let arr5:[{name:string,age:number}]=[{name:"YAP",age:25}]; let arr6:[{name:string,age:number},{name:string,age:number}]=[{name:"YAP",age:25},{name:"DJQ",age:25}];
函数类型
函数类型的约束,支持有函数本身的参数约束和返回值约束。如果想支持联合类型的函数关系,可以使用重载方式。
参数约束和返回值约束

//声明一个 参数约束和返回值约束 的函数。 function funcType(name:string,age:number):number{ return age; } let ageNum:number=funcType("张三",18);
可选参数

function funcType(name:string,age:number,gender?:string):number{ return age; } let ageNum:number=funcType("张三",18); funcType("李四",18,"男");
参数不确定

//如果参数不确定,可以使用扩展运算符的方式来定义动态参数。 function dynFuncType(name:string,age:number,...args:any):any{ console.log(args);//结果:["11","22","33"] return args; } let dynUser:any=dynFuncType("张三",18,"11","22",33);
参数默认值

//与es6一样,区别在于要给参数设置一个类型的约束。 function funcType(name:string="张三",age:number=18):number{ return age; }
表达式类型的函数
let 函数名(参数)=>返回类型=function(参数):类型{...}

//表达式类型的函数 //es6的箭头:let 函数名(参数)=>返回类型=function(参数):类型{...} let funcType2:(name:string,age:number)=>number=function(name:string="张三",age:number=20):number{ return age; }
使用接口来约束函数
let 函数名:接口=function(参数):类型{...}

//定义一个接口 interface IFuncType{ (name:string,age:number):number; } //let 函数名:接口=function(参数):类型{...} let funcType3:IFuncType=function(name:string,age:number):number{ return age; }
联合类型的函数
可以使用重载的方式实现

//重载 function getValue(value:number):number; function getValue(value:string):string; //联合类型的函数 function getValue(value:string|number):string|number{ return value; } let val:string=getValue("张三"); let val2:number=getValue(18);
函数没有返回值

//void 规定函数没有返回值 function fun():void{ let age=20; }
类型断言
手动指定一个值的类型。将一个联合类型的变量,指定为一个更加具体的类型。

/*类型断言*/ //注意:类型断言不是类型转换,断言一个联合类型不存在的类型是不允许的 function getAsset(name:string|number){ return (name as string).length; //使用as,实现类型断言,在jsx(react中的ts版)中使用这种方式。 } getAsset("张三"); getAsset(30);
类型别名
用来给一个类型起一个新名字。采用关键字type定义,可以设置字符串和数值类型。
约束数值类型

type strType=string|number|boolean; let str:strType; str="10"; str=10; str=true;
约束字符串类型

type gender="男"|"女"; function getGender(s:gender):string{ return s; } getGender("男"); //getGender("55"); 会报错
枚举
用于取值被限定在一定范围内的场景。是对JavaScript标准数据类型的一个补充。
定义数值集合,枚举会员会被赋值为0开始递增的数字,同时也会被枚举值到枚举名进行反向映射。

/*枚举*/ enum Days{ Sun, Mon, True, Wed, Thu, Fri, Sat } console.log(Days.Sun); //使用枚举名,可以获取到枚举值 console.log(Days[0]); //使用枚举值0,可以获取到枚举名Sun console.log(Days.Sat); //6 console.log(Days[6]); //Sat console.log(Days); //枚举类型会被编译成一个双向映射的对像
可以手动指定成员的编号

enum Color{ Red=10, Green=9, Blue=1000 } console.log(Color); enum Color2{ Red, //0 Green=9, //9 Blue, //10 } console.log(Color2);
类的修饰符
目的是为了方便阅读代码。
public
共有,全局访问。
private
私有,不能类外访问。
protected
受保护,和private的区别是可以在继承的类中访问。
demo

/*类的修饰符*/ class Person{ public name="张三"; private gener="男"; protected height="175"; age=18; say(){ console.log("我叫:"+this.name); console.log("性别:"+this.gener); //private属性可以类内访问 console.log("身高:"+this.height); //protected属性可以类内访问 } } let p=new Person(); console.log(p.name,p.age); p.say(); //p.gener; 会报错,private属性不可以类外访问 //p.height; 会报错,protected属性不可以类外访问 //定义Person类的子类Child class Child extends Person{ callParent(){ console.log(this.height); //子类内可以访问 父类的protected属性 //console.log(this.gener); 会报错,子类内不可以访问 父类的private属性 } } let c=new Child(); c.callParent();
接口约束类
接口是一种规范的定义。定义了行为和动作。用来约束类,实现高内聚低耦合的代码规范。
类继承接口使用关键字 implements,表示该类是实现类
接口继承接口使用关键字 extends,表示该接口是子接口。
速记,同类继承/同接口继承用extends,表示父子关系。
在接口中定义成员方法

fly() fly:Function fly:Object fly:()=>void
类继承一个接口

interface ISuperMan{ age:number; name:string; fly:Function; } class Man implements ISuperMan{ age:number=30; name:string="超人"; fly(){ console.log(this.name + "在飞"); }; } let man =new Man(); man.fly();
类继承多个接口

interface ISuperMan{ age:number; name:string; fly:Function; } interface IlronMan{ eat:Function } interface ISpiderMan{ run:()=>void } class Man implements ISuperMan,IlronMan,ISpiderMan{ age:number=30; name:string="超人"; fly(){ console.log(this.name + "在飞"); }; eat(){}; run(){}; } let man =new Man(); man.fly();
接口继承多个接口

interface ISuperMan{ age:number; name:string; fly:Function; } interface IlronMan{ eat:Function } interface ISpiderMan{ run:()=>void } //接口继承多个接口 interface IMan extends ISuperMan,IlronMan,ISpiderMan{ } //类继承接口 class Man2 implements IMan{ age:number=30; name:string="超人"; fly(){ console.log(this.name + "在飞"); }; eat(){}; run(){}; }
泛型
在定义函数、接口、类的时候,不预先指定具体类型,在使用的时候再指定类型的一种特性。
比如定义一个带有参数的函数,未来在调用这个函数时,传入的值类型不确定,有可能是string,也有可能是number,这时可以使用泛型来解决这样的问题。

function createArray<T>(length:number,value:T):Array<T>{ //T自定义名称,value:T,T代表未知类型 let arr:any=[]; for(let i=0;i<length;i++){ arr[i]=value; } return arr; } let strArray:string []=createArray<string>(3,"1"); console.log(strArray); //结果 ['1','1','1'] let numArray:number []=createArray<number>(3,2);//如果不传<number>可以进行类型推断 console.log(numArray); //结果 [2,2,2,2]
多个泛型参数的函数

function createMan<T,K>(name:T,age:K):[T,K]{ return [name,age]; } let result=createMan<string,number>("张三",30); console.log(result[0],result[1]); //结果:张三 30
泛型接口
为接口中的属性或方法定义泛型类型。在使用接口时,指定具体的泛型类型。
在函数中的使用

interface ICreate{ <T>(name:string,age:T):string } let func:ICreate=function<T>(name:string,age:T):string{ return name+","+age; } func<number>("李四",20); //结果:李四 20
在类中的使用

//定义一个接口 interface IUser<T>{ name:string; age:number; getUserInfo:()=>T } //定义一个类来继承接口 class User implements IUser<string>{ name: string="李四"; age: number=33; getUserInfo(){ return `姓名${this.name},年龄${this.age}`; } //想要传参就得添加下面这个构造器 constructor(name:string,age:number){ this.name=name; this.age=age; } } let user2=new User("张三",30); console.log(user2.getUserInfo()); //结果:姓名张三,年龄30
泛型类
为类中的属性或方法定义泛型类型。在创建类的实例时,在指定特定的泛型类型。

class Counter<T>{ public num:T; total(price:T,amount:T){ return Number(price)*Number(amount);//如果需要计算,必须转成Number类型。 } } let ctl=new Counter<number>(); ctl.num=0; ctl.total(100,ctl.num); let ct2=new Counter<string>(); ct2.num="100"; ct2.total("200",ct2.num);
泛型约束
指确保泛型类型使用的参数,是提供特定方法的类型。
比如直接对一个泛型参数使用length属性或是用push()方法,会报错。
因为这个泛型根本不知道它有这个属性或是这个方法,使用泛型约束可以解决这一个问题。

interface IArrayFunc{ push:Function; //可以在setArray函数中使用push方法 length:number; //可以在setArray函数中使用length属性 } function setArray<T extends IArrayFunc>(data:T,value:string|number){ data.push(value); console.log(data); //结果为 [1,2,3,'4'] console.log(data.length); //结果为 4 } setArray([1,2,3],"4");
命名空间
避免命名冲突。将相似功能的函数、类、接口等放置到命名空间内。
使用 namespace关键字创建命名空间。
在外部访问命名空间里面的数据,要在数据前面添加export关键字。

namespace A{ export let message="大家好"; export class Person{ public name:string="张三"; public say(){ console.log("大家好,我是"+this.name); } } } console.log(A.message); //结果:大家好 let person=new A.Person(); person.name; //结果:张三 person.say(); //结果:大家好,我是张三