好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

TypeScript知识点

1.1 Typescript 介绍

1.TypeScript 是由微软开发的一款开源的编程语言,像后端 java、C#这样的面向对象语言可以让 js 开发大型企业项目。

2.TypeScript 是 Javascript的超级,遵循最新的 ES6、Es5 规范(相当于包含了es6、es5的语法)。TypeScript扩展了JavaScript的语法。

3.最新的 Vue 、React 也可以集成 TypeScript。

1.2 Typescript 安装 编译

安装nodejs环境,用npm全局安装typescript
 npm  install -g typescript
  
Typescript文件后缀名为.ts,最后将编译成js文件

Typescript手动编译 => tsc + 文件名

 // 将 index.ts编译成 index.js
tsc  index.ts
    

1.3 Typescript开发工具Vscode自动编译.ts 文件

1.3.1 tsc --init 生成配置文件tsconfig.json

1.3.2 点击菜单栏任务-运行任务(遇到错误使用快捷键ctrl + shift + b),点击 tsc:监视-tsconfig.json 然后就可以自动生成代码

typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验

2.1 基础类型

在typescript中主要给我们提供了以下数据类型:

布尔类型(boolean) 
数字类型(number) 
字符串类型(string) 
数组类型(array) 
元组类型(tuple) 
枚举类型(enum) 
任意类型(any) 
null和undefined 
void类型 
never类型

相比于js,typescript中多了枚举类型、任意类型、void类型和never类型

2.2 变量定义

写ts代码变量必须指定类型,指定类型后赋值必须为指定的类型,否则报错

  var flag:boolean =  true
flag =  123  // 错误,类型不一致     

2.3 数据类型

布尔类型(boolean)
  var flag:boolean =  true

flag =  false  // 正确

 // flag=123;  // 错误      
数字类型(number)
  var num:number =  123;

num =  456;  // 正确 

 // num='str';    //错误      
字符串类型(string)
  var str:string =  'this is ts';

str= 'haha';   //正确

 // str=true;  //错误      
数组类型(array) ts中定义数组有两种方式
  // 第一种
 var arr:number[] = [ 1,  2,  3]

 // 第二种
 var arr2: Array<number> = [ 1,  2,  3]            
元组类型(tuple)元素的类型不必相同,写法和数组一样
  let arr:[number,string] = [ 123, 'this is ts']    
枚举类型(enum)

用法:

   enum 枚举名{ 
    标识符[=整型常数], 
    标识符[=整型常数], 
    ... 
    标识符[=整型常数], 
}
   
 enum Flag {success =  1,error =  2};

 let s:Flag = Flag.success  // 使用枚举类型中的值
 console.log( '正确状态',s)
 let f:Flag = Flag.error
 console.log( '错误状态',f)          
任意类型(any)

为那些在编程阶段还不清楚类型的变量指定一个类型

  var number:any =  123
number =  'str'
number =  true     
2.9 null 和 undefined

undefined:

 {
     // 在js中,变量已声明但未初始化为undefined
     var undefinedTest:number
     // console.log(undefinedTest) // 错误写法,typescript报错,赋值了才正确

     // 在typescript中,已声明未初始化的值要直接访问的话类型需要定义为undefined
     var undefinedTest2: undefined
     console.log(undefinedTest2)  // 正确写法,输出undefined 
}
{
     // 可能是number类型 可能是undefined
     var undefinedTest3:number |  undefined;
     console.log(num);
}             

null:

  // null是一个空指针对象,undefined是未初始化的变量。因此,可以把undefined看作是空的变量,而null看作是空的对象
 var nullTest: null
nullTest =  null
 // nullTest = {} // 错误,定义了类型是null,值必须为null      
void类型

typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。

  // 表示方法没有返回任何类型
  function  run( ):  void {
     console.log( 'run')
}

run()         
never类型 表示的是那些永不存在的值的类型,例如异常
  var a:never

 // a = 123 //错误写法
a =  ( () => {
     throw  new  Error( '错误');
})()         

三、Typescript函数

内容概述: 函数的定义、可选参数、默认参数、剩余参数、函数重载、箭头函数。

3.1.1 函数的定义

es5定义函数有函数声明法和匿名函数法
  // 法一:函数声明法

  function  run( ): string {
     return  'run'
}

 /**
// 错误写法
function run():string {
    return 123
}
*/

 // 法二:匿名函数
 var run2 =   function ( ): string {
     return  'run2'
}

 console.log( '函数定义一', run())
 console.log( '函数定义二', run2())                      

3.1.2 ts中定义方法传参

函数传参要指定数据类型
   function  paramFuc( name:string, age:number): string{
     return  ` ${name} ---  ${age}`
}

 console.log( '函数传参', paramFuc( 'dz',  20))              

3.1.3 函数没有返回值的方法用void

   function  voidFnc( ): void{
     console.log( '没有返回值的方法用void')
}
voidFnc();        

3.2 可选参数

es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要在可选参数后加?,这就是可选参数。
   function  electParam( name:string, age?:number): string {
     // 这里的age可传可不传,age就是可选参数
     if(age){
         return  ` ${name} ---  ${age}`
    } else{
         return  ` ${name} --- 年龄保密`
    }
}
 console.log( '可选参数', electParam( 'dz'))

 // 注意: 可选参数必须配置到参数的最后面

 // 错误写法:可选参数不在最后面
 // function electParam2(name?: string, age: number): string {
 //     ...
 // }                        

3.3 默认参数

es5里面没法设置默认参数,es6和ts中都可以设置默认参数
  // age为默认参数
  function  defaultParam( name:string, age:number =  20): String {
     return  ` ${name} ---  ${age}`
}

 console.log( '默认参数', defaultParam( 'dz'))               

3.4 剩余参数

当有很多参数时候或参数个数不确定,可以用三点运算符
  // sum参数传过来的是一个数组
  function  sum( ...result: number[]):  number {
     var sum =  0;

     for ( var i =  0; i < result.length; i++) {

        sum += result[i];
    }

     return sum;
}
 console.log( '剩余参数', sum( 1,  2,  3,  4,  5,  6));

 // a=1 b=2 其他参数为剩余参数
  function  sum2( a: number, b: number, ...result: number[]):  number {
     var sum = a * b;

     for ( var i =  0; i < result.length; i++) {

        sum += result[i];
    }

     return sum;
}
 console.log( '剩余参数2', sum2( 1,  2,  3,  4,  5,  6));                                        

3.5 ts函数重载

同样的函数,传入不同的参数,实现不同的功能 java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。 typescript中的重载:通过为同一个函数提供多个函数类型定义来实现多种功能的目的。 ts为了兼容es5 以及 es6 重载的写法和java中有区别。
  //  es5中同名函数,后面会覆盖前面的函数,ts中则不会 => 函数重载
  function  getInfo( name:string): string
 function  getInfo( name:string, age:number): string
 function  getInfo( name:any, age?:any): any {
     if(age) {
         return  '姓名:' + name +  '年龄:' + age
    } else{
         return  '姓名:' + name
    }
}

 console.log(getInfo( 'dz'))
 console.log(getInfo( 'dz',  20))
 // console.log(getInfo(20)) // 错误                            

3.6 箭头函数

箭头函数和es6中一样

 setTimeout(  () => {
     console.log( '箭头函数')
},  1000);      

四、Typescript中的类

4.1 es5中的类

内容概述:类的创建、静态方法、继承(对象冒充继承,原型链继承,对象冒充 + 原型链组合继承)

es5中的面向对象、构造函数、原型与原型链本质可以看这个文档 http://caibaojian.com/javascr...  , 个人觉得写得很清晰。

4.1.1 类的创建

es5类在构造函数和原型链里都可以添加属性和方法,原型链上的属性会被多个实例所共享,而构造函数则不会。

 
  function  Person( ) {
     this.name =  'Ming'
     this.run =   function( ) {
         console.log( this.name +  '在运动')
    }
}

Person.prototype.sex =  '男'  // 原型链上的属性会被多个实例所共享
Person.prototype.work =   function( ) {
     console.log( this.name +  '在工作')
}


 var p =  new Person()
p.run()
p.work()
 console.log(p.name)
                         

4.1.2 静态方法

调用静态方法不需要实例化
 
Person.getInfo=  function( ){
     console.log( '我是静态方法');
}
Person.getInfo();
      

4.1.3 实现继承

对象冒充(或者叫构造函数继承)继承:可以继承构造函数里面的属性和方法,但是没法继承原型链上面的属性和方法

原型继承:可以继承构造函数里面的属性和方法,也可以继承原型链上面的属性和方法,但是实例化子类的时候没法给父类传参

下面是通过 对象冒充 + 原型链 组合继承,解决了上面两种继承方式存在的问题

 
  function  Worker( name,age){
     this.name=name;   /*属性*/
     this.age=age;
     this.run=  function( ){   /*实例方法*/
        alert( this.name+ '在运动');
    }

}      
Worker.prototype.sex= "男";
Worker.prototype.work=  function( ){
    alert( this.name+ '在工作');
}
    
  function  Web( name,age){
    Worker.call( this,name,age);   // 对象冒充继承,可以继承构造函数里面的属性和方法,实例化子类可以给父类传参
}
 // Web.prototype = new Worker();  // 原型链继承方法一:继承Worker构造函数和原型上所有的方法和属性
Web.prototype = Worker.prototype;   //原型链继承方法二:优化了方法一重复继承构造函数属性和方法的问题(本质可以看看http://caibaojian.com/javascript-object-5.html)

 var w =  new Web( '赵四', 20);   
w.run();
w.work();
                                 

从上面可以看出,对象冒充继承是在子类Web构造函数里面通过call方法继承父类Worker的构造函数的属性和方法;原型链继承通过子类Web的原型对象等于父类Worker的原型对象来实现继承;最后这两种继承的组合方式实现了完美继承。

4.2 typescript中的类

内容概述: ts中类的定义、继承、类修饰符、静态属性和静态方法、多态、抽象类和抽象方法

4.2.1 ts中类的定义

ts中类的定义和es6类的定义一样

 
  class  PersonDefine {
    name: string  // 属性,前面省略了public关键词
     constructor(name:string) {  //构造函数
         this.name = name
    }
    run():string {  // 原型
         return  ` ${ this.name}在运动`
    }
}
 var define =  new PersonDefine( '类的定义')
alert(define.run())
                

4.2.2 继承

ts中继承比es5简单很多,用extends super实现继承
 
  class  WebExtend  extends  PersonDefine {
     constructor(name:string) {
         super(name)  // super继承父类的构造函数,并向父类构造函数传参
    }
    work():string {
         return  ` ${ this.name}在工作`
    }
}

 var extend =  new WebExtend( '继承')
alert(extend.run())
alert(extend.work())
                

4.2.3 ts类里面的修饰符

修饰符:typescript里面定义属性的时候给我们提供了三种修饰符

public: 公有修饰符,在当前类里面、子类、类外面都可以访问 protected:保护类型,在当前类里面、子类里面可以访问,在类外部没法访问 private :私有修饰符,在当前类里面可以访问,子类、类外部都没法访问

注意:属性如果不加修饰符,默认就是公有修饰符

 
 // 以private为例
  class  PersonPrivate{
    private name:string;   /*被private修饰的属性 => 私有属性*/
     constructor(name:string){
         this.name=name;
    }
    run():string{
         return  ` ${ this.name}在运动`  // 私有属性只能在当前类里面可以访问
    }
}

  class  Web  extends  PersonPrivate{
     constructor(name:string){
         super(name)
    }
    work(){
         // return `${this.name}在工作` // 报错,子类不能访问父类的私有属性
    }
}
 
 var privateName =  new PersonPrivate( 'private')
alert(privateName.run())
 // console.log(privateName.name) // 报错,外部不能访问类的私有属性
                         

4.2.4 静态属性和静态方法

为什么要用静态属性和静态方法?jq里面的$.ajax就是用的静态方法
 
  function  $( element) {
     return  new Base(element)
}

  function  Base( element) {
     this.element =  document.getElementById(element)
     this.css =   function( arr, value) {
         this.element.style[arr] = value
    }
}
$( 'box').css( 'color', 'red')
$.ajax =   function( ) {}   // 想要在$上使用方法怎么办,用静态方法
                         
ts中实现静态属性和静态方法用static
 
  class  PersonStatic{
     /*公有属性*/
    public name:string;
     constructor(name:string) {
         this.name=name;
    }
     /*实例方法(需要被实例化,所以为实例方法)*/
    run(){  
         return  ` ${ this.name}在运动`
    }
     /*静态属性*/
     static sex =  '男'
     /*静态方法,里面没法直接调用类里面的属性*/
     static info(){  
         // return 'info方法' + this.name  // 静态方法不能调用本类的方法和属性,可以调用静态属性
         return  'info方法' + PersonStatic.sex
    }
}

 console.log( '静态方法' + PersonStatic.info())
 console.log( '静态属性' + PersonStatic.sex)
                        

4.2.5 多态

父类定义一个方法不去实现,让继承它的子类去实现,每一个子类的该方法有不同的表现 多态属于继承

比如定义一个父类Animal,里面的eat方法不去实现,让子类Dog和Cat分别实现自己的eat方法

 
  class  Animal {
    name:string;
     constructor(name:string) {
         this.name=name;
    }
    eat(){    // eat方法继承它的子类去实现
    }
}
  class  Dog  extends  Animal{
     constructor(name:string){
         super(name)
    }
    eat(){
         return  this.name+ '吃粮食'
    }
}

  class  Cat  extends  Animal{
     constructor(name:string){
         super(name)
    }
    eat(){
         return  this.name+ '吃老鼠'
    }
}
                           

4.2.6 抽象类和抽象方法

定义:用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类(抽象类的子类)中实现 抽象类:它是提供其他类继承的基类,不能直接被实例化,子类继承可以被实例化 abstract修饰的方法(抽象方法)只能放在抽象类里面 抽象类和抽象方法用来定义标准(比如定义标准为:抽象类Animal有抽象方法eat,要求它的子类必须包含eat方法)
 
abstract   class  AnimalAbst{
    public name:string;
     constructor(name:string){
         this.name=name;
    }
    abstract eat():any;   //抽象方法不包含具体实现并且必须在派生类中实现
    run(){
         console.log( '其他方法可以不实现')
    }
}
 // var a = new Animal() /*错误的写法,抽象类不能被实例化*/

  class  DogAbst  extends  Animal{
     //抽象类的子类必须实现抽象类里面的抽象方法
     constructor(name:any){
         super(name)
    }
    eat(){
         return  this.name +  '吃粮食'
    }
}

 var d =  new DogAbst( '小花花');
 console.log( '抽象类和抽象方法',d.eat());
                          

五、TypesSript接口

接口定义 :接口是对传入参数进行约束;或者对类里面的属性和方法进行声明和约束,实现这个接口的类必须实现该接口里面属性和方法;typescript中的接口用interface关键字定义。

接口作用:接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

内容概述:接口分类:(属性接口、函数类型接口、可索引接口、类类型接口),接口的继承

5.1 接口分类

5.1.1 属性接口

对传入对象的约束(也就是对json的约束)

在了解接口之前,我们来看看函数传入obj参数

 
  function  printLabel( labelInfo: {label:string}){
     return labelInfo
}
 // printLabel({name:'obj'});  //错误的写法
 console.log(printLabel({ label:  'obj'}))
          

和上面类似,由此引入属性接口 => 对方法传入参数进行约束

下面为属性接口的例子,方法printFullName对传入参数FullName(为对象)进行约束

 
interface FullName{
     firstName: string;  // 注意;结束
    secondName: string;
    age?: number  // 接口的可选属性用?
}

  function  printFullName( name:FullName) {
     // 传入对象必须包含firstName和secondName,可传可不传age
     return name
}
 var obj = {
     firstName: '小',
     secondName: '明',
     age:  20
}
 console.log(printFullName(obj))
                  

属性接口应用:原生js封装ajax

 
interface Config{
     type: string;
    url: string;
    data?: string;
    dataType: string;
}
  function  ajax( config: Config) {
     var xhr =  new XMLHttpRequest
    xhr.open(config.type, config.url,  true)
    xhr.send(config.data)
    xhr.onreadystatechange =   function( ) {
         if(xhr.readyState ==  4 && xhr.status ==  200) {
             if(config.dataType ==  'json'){
                 console.log( JSON.parse(xhr.responseText))
            } else{
                 console.log(xhr.responseText)
            }
        }
    }
}

ajax({
     type:  'get',
     data:  'name=xiaoming',
     url:  'http://a.itying.com/api/productlist',
     dataType:  'json'
})
                             

5.1.2 函数类型接口

对方法传入的参数以及返回值进行约束
 
interface encrypt{
    (key: string,  value: string): string;  // 传入的参数和返回值的类型
}

 var md5:encrypt =   function( key:string, value:string): string{
     // encrypt对加密方法md5进行约束,同时md5方法的参数和返回值类型和encrypt要保持一致
     return key + value
}

 console.log(md5( 'name',  '小明'))
             

5.1.3 可索引接口

对索引和传入参数的约束(一般用于对数组、对象的约束)

ts中定义数组:

 
 var arr1:number[] = [ 1, 2]
 var arr2: Array<string> = [ '1',  '2']
        

现在用接口来实现:

 
 // 对数组的的约束
interface UserArr{
     // 索引为number,参数为string
    [index:number]: string
}
 var userarr:UserArr = [ 'a',  'b']
 console.log(userarr)
       
 
 // 对象的约束
interface UserObj{
     // 索引为string,参数为string
    [index:string]: string
}
 var userobj:UserObj = {  name:  '小明',  sex:  '男' }
 console.log(userobj)
         

5.1.4 类类型接口

对类的约束,和抽象类抽象有点相似
 
interface Animal{
     // 对类里面的属性和方法进行约束
    name:string;
    eat(str:string): void;
}
 // 类实现接口要用implements关键字,必须实现接口里面声明的方法和属性
  class  Cat  implements  Animal{
    name:string;
     constructor(name:string){
         this.name = name
    }
    eat(food:string){
         console.log( this.name +  '吃' + food)
    }
}
 var cat =  new Cat( '小花')
cat.eat( '老鼠')
                  

5.2 接口的继承

和类的继承一样,用extends实现接口继承

下面同时实现类的继承和接口的继承

 
interface Animal {
    eat():  void;
}
 // 继承Animal接口,则实现Person接口的类必须也实现Animal接口里面的方法
interface Person extends Animal {
    work():  void;
}

  class  Programmer {
    public name: string;
     constructor(name: string) {
         this.name = name;
    }
    coding(code: string) {
         console.log( this.name + code)
    }
}

 // 继承类并且实现接口
  class  Web  extends  Programmer  implements  Person {
     constructor(name: string) {
         super(name)
    }
    eat() {
         console.log( this.name +  '吃')
    }
    work() {
         console.log( this.name +  '工作');
    }
}

 var w =  new Web( '小李');
w.eat();
w.coding( '写ts代码');
                               

六、TypesSript泛型

泛型定义 :泛型定义:泛型就是解决类、接口、方法的复用性,以及对不特定数据类型的支持(类型校验)。ts中用T表示泛型。

泛型公式: <T>表示泛型,调用的时候指定T的数据类型

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

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

内容概述:内容概述:函数的泛型、类的泛型、泛型接口

6.1 函数的泛型

传入的参数类型和返回的参数类型可以指定

我们来看看函数用ts数据类型,想要同时返回string类型和number类型

 
  function  getData1( value:string): string{
     return value;
}
  function  getData2( value:number): number{
     return value;
}
             

这样要写不同的函数,不能按照需求返回不同类型数据,造成代码冗余 => 由此引入泛型

<T>表示泛型,调用的时候指定T的数据类型
 
  function  dataT< T>( value:T): T{
     // 传入参数为T 返回值为T
     return value
}
dataT<number>( 1)  // 调用指定泛型为number类型,则传入参数也必须为number类型
dataT<string>( 'string')

  function  dataAny< T>( value:T): any{
     return  '传入参数为T,任意类型返回值';
}
dataAny<number>( 123);  // 参数必须是number
dataAny<string>( '这是一个泛型');
                       

6.2 类的泛型

也是用<T>来实现类的泛型,new的时候指定T的数据类型

有个最小堆算法,需要同时支持返回数字和字符串两种类型

使用泛型之前:只能在类的类部指定数据类型,实现需求还要写一套string类型的类

 
  class  MinClass{
    public list:number[]=[];
    add(num:number){
         this.list.push(num)
    }
    min():number{
         var minNum= this.list[ 0];
         for( var i= 0;i< this.list.length;i++){
             if(minNum> this.list[i]){
                minNum= this.list[i];
            }
        }
         return minNum;
    }
}

 var m= new MinClass();
m.add( 1);
m.add( 2);
alert(m.min());
                    

使用泛型之后:只用一套类来实现

 
  class  MinClassT< T>{
    public list:T[]=[];
    add(value:T): void{
         this.list.push(value);
    }
    min():T{        
         var minNum= this.list[ 0];
         for( var i= 0;i< this.list.length;i++){
             if(minNum> this.list[i]){
                minNum= this.list[i];
            }
        }
         return minNum;
    }
}
 var m1= new MinClassT<number>();    /*实例化类 并且指定了类的T代表的类型是number*/
m.add( 1);
m.add( 2);
alert(m1.min())

 var m2= new MinClassT<string>();    /*实例化类 并且指定了类的T代表的类型是string*/
m2.add( 'c');
m2.add( 'a');
alert(m2.min())
                            

6.3 泛型接口

有一个函数类型接口

 
interface ConfigFn{
    (value:string):string;
}
 var setData:ConfigFn =   function( value:string): string{
     return value
}
setData( 'name');
 // setData(20); // 错误
         

setData(20);写法错误,想要传入number类型的参数又要写一个函数类型接口 => 用泛型接口

泛型接口有两种写法:

 
 // 泛型接口定义方式一
interface ConfigFnOne{
    <T>(value:T):T;
}
 var setDataOne:ConfigFnOne =   function< T>( value:T): T{
     return value
}
 // 既可以传入string也可以传入number类型参数
setDataOne<string>( 'name');
setDataOne<number>( 20);
            
 
 // 泛型接口定义方式二
interface ConfigFnTwo<T>{
    (value:T):T;
}
  function  setDataTwo< T>( value:T): T{
     return value
}
 var setDataTwoFn:ConfigFnTwo<string> = setDataTwo
setDataTwoFn( 'name');
           

示例代码请查看github,欢迎start  https://github.com/dzfrontend...

查看更多关于TypeScript知识点的详细内容...

  阅读:54次