TypeScript是微软开发的自由和开源的编程语言。他是javascript的一个超集,而本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。
下边是ts和es系列的关系还有区别:
基础类型类型分类Boolean类型
Number类型
String类型
Symbol类型
Array类型
Enum类型
Any类型
Unknow类型
Tuple类型
Void类型
Null和Undefined类型
object,Object和{}类型
Never类型
定义类型使用Boolean,Number,String
letcount:number=10;//ES5:varcount=10;Symbolconstsym=Symbol();letobj={[sym]:"semlinker",};console.log(obj[sym]);//semlinker
Array
letlist:number[]=[1,2,3];//ES5:varlist=[1,2,3];letlist:Arraynumber=[1,2,3];//Arraynumber泛型语法//ES5:varlist=[1,2,3];
Enum
enumDirection{NORTH="NORTH",SOUTH="SOUTH",EAST="EAST",WEST="WEST",}letdir:Direction=Direction.NORTH;console.log(Direction){NORTH:NORTH,SOUTH:SOUTH,EAST:EAST,WEST:WEST}
AnyUnkonwn
letvalue:any;value.foo.bar;//OKvalue.trim();//OKvalue();//OKnewvalue();//OKvalue[0][1];//OKletvalue:unknown;value=true;//OKvalue=42;//OKvalue="HelloWorld";//OKvalue=[];//OKvalue={};//OKvalue=Math.random;//OKvalue=null;//OKvalue=undefined;//OKvalue=newTypeError();//OKletvalue1:unknown=value;//OKletvalue2:any=value;//OKletvalue3:boolean=value;//Errorletvalue4:number=value;//Errorletvalue5:string=value;//Error
Tuple
数组?般由同种类型的值组成,但有时我们需要在单个变量中存储不同类型的值,这时候我们就可以使?元组。在JavaScript中是没有元组的,元组是TypeScript中特有的类型,其?作?式类似于数组。
lettupleType:[string,boolean];tupleType=["semlinker",true];
Void
void类型像是与any类型相反,它表示没有任何类型。当?个函数没有返回值时,你通常会?到其返回值类型是void:
需要注意的是,声明?个void类型的变量没有什么作?,因为在严格模式下,它的值只能为undefined:
//声明函数返回值为voidfunctionwarnUser():void{console.log("Thisismywarningmessage");}letunusable:void=undefined;Null和UndefinedTypeScript?,undefined和null两者有各?的类型分别为undefined和null。letu:undefined=undefined;letn:null=null;
object,Object和{}
Never
never类型表示的是那些永不存在的值的类型。例如,never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型
联合类型letnum:1
2=1;typeEventNames=click
scroll
mousemove;
可辨识联合
它包含3个要点:可辨识、联合类型和类型守卫。
交叉类型交叉类型是将多个类型合并为?个类型。通过运算符可以将现有的多种类型叠加到?起成为?种类型,它包含了所需的所有类型的特性
typePartialPointX={x:number;};typePoint=PartialPointX{y:number;};letpoint:Point={x:1,y:1}
如果有同名基础类型属性合并,那么合并后的类型为never类型。比如:
interfaceX{c:string;d:string;}interfaceY{c:number;e:string}typeXY=XY;typeYX=YX;letp:XY;letq:YX;
在上?的代码中,接?X和接?Y都含有?个相同的成员c,但它们的类型不?致。对于这种情况,此时XY类型或YX类型中成员c的类型是不是可以是string或number类型呢?结论下边:
为什么接?X和接?Y混?后,成员c的类型会变成never呢?这是因为混?后成员c的类型为stringnumber,即成员c的类型既可以是string类型?可以是number类型。很明显这种类型是不存在的,所以混?后成员c的类型为never。
类型别名typeMessage=string
string[];letgreet=(message:Message)={//...};
Typescript断言
类型断?好?其他语??的类型转换,但是不进?特殊的数据检查和解构。它没有运?时的影响,只是在编译阶段起作?。
类型断言
非空断言
确定赋值断言
类型断言尖括号断言
letsomeValue:any="thisisastring";letstrLength:number=(stringsomeValue).length;
as断言
letsomeValue:any="thisisastring";letstrLength:number=(someValueasstring).length;
确定赋值断言
letx!:number;initialize();console.log(2*x);//Okfunctioninitialize(){x=10;}
通过letx!:number;确定赋值断?,TypeScript编译器就会知道该属性会被明确地赋值。
非空断言操作符
x!将从x值域中排除null和undefined。
类型守卫in关键词
typeof关键词
instanceof关键词
自定义类型保护的类型谓词
in关键词interfaceAdmin{name:string;privileges:string[];}interfaceEmployee{name:string;startDate:Date;}typeUnknownEmployee=Employee
Admin;functionprintEmployeeInformation(emp:UnknownEmployee){console.log("Name:"+emp.name);if("privileges"inemp){console.log("Privileges:"+emp.privileges);}if("startDate"inemp){console.log("StartDate:"+emp.startDate);}}
typeof关键词
functionpadLeft(value:string,padding:string
number){if(typeofpadding==="number"){returnArray(padding+1).join("")+value;}if(typeofpadding==="string"){returnpadding+value;}thrownewError(`Expectedstringornumber,got{padding}.`);}
instanceof关键字
interfacePadder{getPaddingString():string;}classSpaceRepeatingPadderimplementsPadder{constructor(privatenumSpaces:number){}getPaddingString(){returnArray(this.numSpaces+1).join("");}}classStringPadderimplementsPadder{constructor(privatevalue:string){}getPaddingString(){returnthis.value;}}letpadder:Padder=newSpaceRepeatingPadder(6);if(padderinstanceofSpaceRepeatingPadder){//padder的类型收窄为SpaceRepeatingPadder}
自定义
functionisNumber(x:any):xisnumber{returntypeofx==="number";}functionisString(x:any):xisstring{returntypeofx==="string";}
函数ts函数和js函数区别参数类型和返回类型
functioncreateUserId(name:string,id:number):string{returnname+id;}
函数类型
letIdGenerator:(chars:string,nums:number)=string;functioncreateUserId(name:string,id:number):string{returnname+id;}IdGenerator=createUserId;
可选参数及默认参数
在声明函数时,可以通过?号来定义可选参数,?如age?:number这种形式。在实际使?时,需要注意的是可选参数要放在普通参数的后?,不然会导致编译错误。
//可选参数functioncreateUserId(name:string,id:number,age?:number):string{returnname+id;}//默认参数functioncreateUserId(name="semlinker",id:number,age?:number):string{returnname+id;}
剩余参数
functionpush(array,...items){items.forEach(function(item){array.push(item);});}leta=[];push(a,1,2,3);
数组数组解构
letx:number;lety:number;letz:number;letfive_array=[0,1,2,3,4];[x,y,z]=five_array;
数组展开运算符
lettwo_array=[0,1];letfive_array=[...two_array,2,3,4];
数组遍历
letcolors:string[]=["red","green","blue"];for(letiofcolors){console.log(i);}接口类型别名
在?向对象语?中,接?是?个很重要的概念,它是对?为的抽象,?具体如何?动需要由类去实现。TypeScript中的接?是?个?常灵活的概念,除了可?于对类的?部分?为进?抽象以外,也常?于对对象的形状(Shape)」进?描述。
基础定义
interfacePerson{name:string;age:number;}letsemlinker:Person={name:"semlinker",age:33,};
可选只读属性
interfacePerson{readonlyname:string;age?:number;}
只读属性?于限制只能在对象刚刚创建的时候修改其值。此外TypeScript还提供了ReadonlyArrayT类型,它与ArrayT相似,只是把所有可变?法去掉了,因此可以确保数组创建后再也不能被修改。
leta:number[]=[1,2,3,4];letro:ReadonlyArraynumber=a;ro[0]=12;//error!ro.push(5);//error!ro.length=;//error!a=ro;//error!
任意属性
[propName:string]:any;interfacePerson{name:string;age?:number;[propName:string]:any;}constp1={name:"semlinker"};constp2={name:"lolo",age:5};constp3={name:"kakuqo",sex:1}类类的概念
类(Class):定义了一件事物的抽象特点,包含它的属性和方法
对象(Object):类的实例,通过new生成
面向对象(OOP)的三大特性:封装、继承、多态
封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如Cat和Dog都继承自Animal,但是分别实现了自己的eat方法。此时针对某一个实例,我们无需了解它是Cat还是Dog,就可以直接调用eat方法,程序会自动判断出来应该如何执行eat
存取器(gettersetter):用以改变属性的读取和赋值行为
修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如public表示公有属性或方法
抽象类(AbstractClass):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口
基础定义classGreeter{//静态属性staticcname:string="Greeter";//成员属性greeting:string;//构造函数-执?初始化操作constructor(message:string){this.greeting=message;}//静态?法staticgetClassName(){return"ClassnameisGreeter";}//成员?法greet(){return"Hello,"+this.greeting;}}letgreeter=newGreeter("world");
编译后
"usestrict";varGreeter=/**
class*/(function(){//构造函数-执?初始化操作functionGreeter(message){this.greeting=message;}//静态?法Greeter.getClassName=function(){return"ClassnameisGreeter";};//成员?法Greeter.prototype.greet=function(){return"Hello,"+this.greeting;};//静态属性Greeter.cname="Greeter";returnGreeter;}());vargreeter=newGreeter("world");私有字段
classPerson{#name:string;constructor(name:string){this.#name=name;}greet(){console.log(`Hello,mynameis{this.#name}!`);}}letsemlinker=newPerson("Semlinker");semlinker.#name;
与常规属性(甚?使?private修饰符声明的属性)不同,私有字段要牢记以下规则:
私有字段以#字符开头,有时我们称之为私有名称;
每个私有字段名称都唯?地限定于其包含的类;
不能在私有字段上使?TypeScript可访问性修饰符(如public或private);
私有字段不能在包含的类之外访问,甚?不能被检测到。
访问器letpasscode="HelloTypeScript";classEmployee{private_fullName:string;getfullName():string{returnthis._fullName;}setfullName(newName:string){if(passcodepasscode=="HelloTypeScript"){this._fullName=newName;}else{console.log("Error:Unauthorizedupdateofemployee!");}}}letemployee=newEmployee();employee.fullName="Semlinker";if(employee.fullName){console.log(employee.fullName);}
类的继承
classAnimal{name:string;constructor(theName:string){this.name=theName;}move(distanceInMeters:number=0){console.log(`{this.name}moved{distanceInMeters}m.`);}}classSnakeextendsAnimal{constructor(name:string){super(name);//调??类的构造函数}move(distanceInMeters=5){console.log("Slithering...");super.move(distanceInMeters);}}letsam=newSnake("SammythePython");sam.move();
抽象类
使?abstract关键字声明的类,我们称之为抽象类。抽象类不能被实例化,因为它??包含?个或多个抽象?法。所谓的抽象?法,是指不包含具体实现的?法,抽象类不能被直接实例化
abstractclassPerson{constructor(publicname:string){}//抽象?法abstractsay(words:string):void;}//Cannotcreateaninstanceofanabstractclass.()constlolo=newPerson();//ErrorclassDeveloperextendsPerson{constructor(name:string){super(name);}say(words:string):void{console.log(`{this.name}says{words}`);}}constlolo=newDeveloper("lolo");lolo.say("Ilovets!");//lolosaysIlovets!
类方法重载
classProductService{getProducts():void;getProducts(id:number):void;getProducts(id?:number){if(typeofid===number){console.log(`获取id为{id}的产品信息`);}else{console.log(`获取所有的产品信息`);}}}constproductService=newProductService();productService.getProducts();//获取id为的产品信息productService.getProducts();//获取所有的产品信息
泛型
在像C#和Java这样的语?中,可以使?泛型来创建可重?的组件,?个组件可以?持多种类型的数据。这样?户就可以以??的数据类型来使?组件。
泛型语法就像传递参数?样,我们传递了我们想要?于特定函数调?的类型。
参考上?的图?,当我们调?identity(1),Number类型就像参数1?样,它将在出现T的任何位置填充该类型。图中内部的T被称为类型变量,它是我们希望传递给identity函数的类型占位符,同时它被分配给value参数?来代替它的类型:
此时T充当的是类型,?不是特定的Number类型。其中T代表Type,在定义泛型时通常?作第?个类型变量名称。但实际上T可以?任何有效名称代替。除了T之外,以下是常?泛型变量代表的意思:
K(Key):表示对象中的键类型;
V(Value):表示对象中的值类型;
E(Element):表示元素类型。
functionidentityT,U(value:T,message:U):T{console.log(message);returnvalue;}console.log(identityNumber,string(68,"Semlinker"));
除了为类型变量显式设定值之外,?种更常?的做法是使编译器?动选择这些类型,从?使代码更简洁。我们可以完全省略尖括号,?如:
functionidentityT,U(value:T,message:U):T{console.log(message);returnvalue;}console.log(identity(68,"Semlinker"));
泛型接口
interfaceGenericIdentityFnT{(arg:T):T;}
泛型类
classGenericNumberT{zeroValue:T;add:(x:T,y:T)=T;}letmyGenericNumber=newGenericNumbernumber();myGenericNumber.zeroValue=0;myGenericNumber.add=function(x,y){returnx+y;};
泛型工具类型
高级内置工具类型
typeofkeyofininferextendsPartial开发辅助JSONTOTS简介:?款TypeScript在线?具,利?它你可以为指定的JSON数据?成对应的TypeScript接?定义。
在线