当前位置: 首页 > Web前端 > HTML5

TypeScript(四)——函数-接口-类-泛型语法总结

时间:2023-04-05 14:15:45 HTML5

类函数类型函数声明函数类型表达式可选参数任意数量的参数&动态成员类需要声明类的属性和方法类成员访问修饰符(public/private/protected)定义构造函数来初始化实例对象并访问构造函数成员创建子类继承构造函数并访问其成员类的结构函数是私有化类的只读属性类和接口定义接口实现接口抽象类抽象classesdefinesubclassinheritanceConstraints,parametersandreturnvaluefunctiondeclaration//参数的类型和返回值函数的类型func1(a:number,b:number):string{return'func1'}//参数类型andnumber是固定的,否则错误func1(100,200)functiontypeexpression//普通函数constfunc4=function(a:number,b:number):string{return'func2'}//使用箭头函数constfunc5:(a:number,b:number)=>string=function(a,b){return'func2'}可选参数可选参数必须放在强制参数之后和函数的末尾。//可以在b后面加问号表示可选,也可以直接设置默认值,也可以不传函数func2(a:number,b:number=10,c?:number):string{return'func1'}func1(100)任意数量的参数使用ES6restoperatorfunctionfunc3(a:number,b:number=10,...rest:number[]):string{return'func1'}func1(100,200,300,400)接口(interface)接口是一种规范、契约,以及约定对象的结构。接口用于约束对象的结构。如果我们想使用这个接口,我们必须遵循它的所有约定。接口最直观的体现就是一个对象应该有哪些成员,它们的类型是什么?Defineaninterface//定义一个接口,必须有两个成员,并且都是字符串类型interfacePost{title:string//结尾可以用逗号分隔,也可以用分号分隔,也可以省略。content:string}使用接口//使用接口时声明参数为Post类型,使用时不用担心没有值functionprintPost(post:Post){console.log(post.title)console.log(post.content)}//title或content有一个没有传过来或者不是字符串会报错printPost({title:'thisisatitle',content:'thisisacontent'})optionalmember&read-onlymember&dynamicmemberoptionalmember:定义接口时加问号,传参时可选interfacePost{title:stringcontent:stringsubtitle?:string//optional可选成员,可选,stringorundefined}//下面不传subtitle不会报错。consthello:Post={title:'thisisatitle',content:'thisisacontent'}read-onlymember:definition在接口前加上readonly关键字。一旦定义,就不能修改。interfacePost{title:stringcontent:stringsubtitle?:stringreadonlysummary:string//只读成员,一旦定义,不可更改}consthello:Post={title:'这是一个标题',content:'thisisacontent',summary:'thisisasummary'}hello.summary='hello'//报错动态成员:不确定有哪些成员,自己定义添加,一般this都存在于动态对象中,比如作为程序Cache中的缓存对象不知道自己有哪些成员名,所以在Cache中使用[],指定keyprop的类型为string,value的类型为numberinterfaceCache{[prop:string]:number}constcache:Cache={}cache['hello']=1cache['hi']=2类是用来描述一类具体事物的抽象特征。TypeScript增强了类的相关语法、访问修饰符和抽象类的概念等。我们来看看TypeScript的新内容:声明类的属性和方法的目的是将属性和方法标记为类型classPerson{//需要声明类的属性,可以加也可以不加默认值。//两者有一个不写,会报错这里如果直接使用会报错,因为TypeScipt需要指定属性,而不是动态添加this.name=namethis.age=age}//方法和之前一样,还必须添加类型注解sayHi(msg:string):void{console.log(`Iam${this.name},${msg}`)}run():void{this.sayHi('Iamhappy!')}}类成员访问修饰符(public/private/protected)-publicprivateprotected内部访问Cocoa外部访问Cocoa子类访问Cocoa1.定义一个构造函数classPerson{//默认为public,有无效果同理,建议加上publicname:string='initname'//age属性为私有属性,函数内部可以通过this.age访问私有属性privateage:number//受保护,外部成员不可访问,子类成员可以访问受保护gender:booleanconstructor(name:string,age:number){this.name=namethis.age=agethis.gender=true}sayHi(msg:string):void{console.log(`我是${this.name},${msg}`)控制台.log(this.age)//内部访问私有属性没有问题console.log(this.gender)//内部访问保护属性没有问题}}2.初始化实例对象,访问构造函数成员constxm=newPerson('xm',18)console.log(xm.name)console.log(xm.age)//错误,属性'age'是私有的,只能在类'Person'中访问c??onsole.log(xm.gender)//错误,属性'gender'受保护,只能在类'Person'及其子类中访问。3.创建子类继承构造函数并访问其成员//定义一个Student类继承PersonclassStudentextendsPerson{constructor(name:string,age:number){super(name,age)console.log(this.gender)console.log(this.age)//错误,私有成员不能访问console.log(this.name)}}Theconstructoroftheclassisprivatizedprivate:如果类的构造函数被私有化,则无法实例化和继承。这时只能在类内部添加一个静态方法,通过静态方法protected添加实例:如果类的构造函数是protected的,那么不能实例化,但是可以继承。classStudentextendsPerson{privateconstructor(name:string,age:number){super(name,age)console.log(this.gender)console.log(this.name)}//你可以定义一个方法来实例化staticcreate(name:string,age:number){returnnewStudent(name,age)}}constxm=Student.create('xm',18)console.log(xm.name)类之前的只读属性attribute加上修饰符readonly,如果有访问修饰符,则跟在修饰符后面。只读属性必须在声明时或在构造函数中初始化。classPerson{publicname:string='initname'privateage:number//如果有访问修饰符,则跟在修饰符protectedreadonlygender:booleanconstructor(name:string,age:number){this.name=namethis.age=agethis.gender=true}sayHi(msg:string):void{console.log(`我是${this.name},${msg}`)console.log(this.gender=false)//不能分配给'gender'因为它是一个只读属性。}run():void{this.sayHi('Iamhappy!')}}letxm=newPerson('xm',18)xm.gender='false'//报错类和接口类的共同点一般都是通过接口抽象出来的。比如下面两个不同的类,有两个相同的eat和run方法,可以使用接口来约束两个类的公共部分classPerson{eat(food:string):void{console.log(`优雅的用餐:${food}`)}run(distance:number){console.log(`uprightWalking:${distance}`)}}classAnimal{eat(food:string):void{console.log(`不优雅eating:${food}`)}run(distance:number){console.log(`Crawling:${distance}`)}}Defineinterface//可以定义一个接口来实现一个能力,然后让一个类实现多个接口interfaceEat{eat(food:string):void}interfaceRun{run(distance:number):void}implementstheinterface//Person和Animal需要实现接口,如果接口对应的方法少,会报错classPersonimplementsEat,Run{eat(food:string):无效{控制台。log(`优雅用餐:${food}`)}run(distance:number){console.log(`直立行走:${distance}`)}}classAnimalimplementsEat,Run{eat(food:string):void{console.log(`Inelegantdining:${food}`)}run(distance:number){console.log(`Crawling:${distance}`)}}抽象类抽象类有点类似于接口,而也是约束哪些成员必须在子类中。不同之处在于抽象类可以包含一些具体的实现。抽象类只能继承不能实例化对象。抽象类中可以定义一些抽象方法。抽象方法不需要方法体。当父类中有抽象方法时,子类必须实现抽象方法Abstractclassdefinition//加上abstract关键字后,就变成了抽象类abstractclassAnimal{eat(food:string):void{console.log(`noteleganteating:${food}`)}//抽象类中可以定义一些抽象方法,关键字abstractabstractrun(distance:number):void}subclassinheritsclassDogextendsAnimal{//可以在VSCode环境下点击DogUsequickfixes自动生成代码实现//这里实现了抽象类中run的抽象方法run(distance:number):void{console.log('crawling',distance)}}//子类实例化constd=newDog()d.eat('grain')d.run(100)泛型当我们定义函数、接口或类时,我们不指定类型。我们只在使用时指定该类型的一个特性。它的目的是在很大程度上重用我们的代码。例如:下面是输入的长度和值,返回一个数组//参数长度为number类型,value为number类型,返回一个number类型的数组functioncreateArray(length:number,value:number):number[]{constarr=Array(length).fill(value)returnarr}//可以传入如下参数,得到三个数值类型的const数组,值为100res=createArray(3,100)//res=>[100,100,100]上面的代码有一个缺陷,它只能返回一个数值类型的数组。如果换成别的类型,会报错。如何修改?definegeneric类型参数函数名后用尖括号,里面定义了泛型参数。一般泛型参数使用大写的T作为名字,T用于函数中有歧义的类型,表示functioncreateArray(length:number,value:T):T[]{constarr=Array(length).fill(value)returnarr}调用时,传入调用时泛型参数的类型,在函数名后面用尖括号填写参数的类型//下面可以填字符串类型或者数字typeconstres=createArray(3,'foo')constres1=createArray(3,100)总结就是泛型参数使用无法明确定义的参数AT代替,使用时指定T的类型TypeScript学习地图