好得很程序员自学网

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

TypeScript入门三:TypeScript函数类型

TypeScript函数类型 TypeScript函数的参数 TypeScript函数的this与箭头函数 TypeScript函数重载

 一、TypeScript函数类型

 在上一篇博客中已经对声明TypeScript类型变量已经做了初步的解析,这里先回顾以下:

  1   //  声明函数 
  2   function   add1(x:number,y:number):number{
   3     return  x+ y;
   4   }
   5  
  6  let add2 =  function  (x:number,y:number):number{
   7     return  x +  y;
   8   }
   9  
 10   //  定义函数类型 
 11  type myAdd = (baseValue: number, increment: number) =>  number;
  12   //  根据函数类型声明函数变量 
 13  let myAdd1:myAdd =  function  (x:number,y:number) : number{
  14     return  x +  y;
  15   }
  16  let myAdd2:myAdd =  function  (x:number,y:number) : number{
  17     return  x -  y;
  18   }
  19  
 20  let hintStamp(str:string): void  {
  21     console.log(str);
  22  }

关于函数类型有一点需要注意,需要使用type关键字并使用等号"="赋值类型;如果使用let声明并使用冒号冒“:”表示的是声明一个函数变量,并且这个函数变量有指定的类型,这个变量不能作为函数类型,只能给它自己赋值指定类型的函数。

 二、TypeScript函数的参数

2.1 根据函数类型声明的函数变量,函数的实际参数名称可以不与函数类型的参数名称一致,这一点与对象类型Object的字段有点区别;

 1  type myAdd = (baseValue: number, increment: number) =>  number;
  2  let myAdd1:myAdd =  function  (a:number,b:number) : number{
  3     return  a +  b;
  4   }
  5  let myAdd2:myAdd =  function  (x:number,y:number) : number{
  6     return  x -  y;
  7  }

2.2 可选参数与默认参数:

这部非内容在官方文档中有详细的说明,这里简要的解析以下,如果有不明白的建议查看官方文档。

可选参数意思就是函数的参数在实际调用函数时,可以不需要全部对应传入,但是在定义函数类型时,必须设定默认参数。

 1   //  示例:在定义函数类型时,给参数b设定了默认参数:'TypeScript' 
 2   function  foo (a: string,b = 'TypeScript'):  void  {
  3    console.log(a + ':' +  b);
  4   }
  5  foo('hello'); //  hello:TypeScript 

设置了默认参数,就不需要设置参数的类型了,TypeScript的IDE会主动为我们推断出参数的类型,也就是默认值的类型,如果给可选参数传值就必须对应默认参数的类型。

除了设置既定的默认参数以外,还可以使用(参数名+?)的方式设置非特定参数,但是设置默认非特定参数需要设置默认参数的类型(参数名?:类型)。这种不设定特定值的可选参数,调用函数时不给这个可选参数传值的话就会默认为undefined。

  1   //  这是官方文档中的一个示例: 
  2   function  buildName(firstName: string, lastName? : string) {
   3     if   (lastName){
   4      
  5       return  firstName + " " +  lastName;
   6    } else  {
   7       return   firstName;
   8     }   
   9   }
  10  
 11  let result1 = buildName("Bob");   //   works correctly now 
 12   console.log(result1);
  13  let result2 = buildName("Bob", "Adams", "Sr.");   //   error, too many parameters 
 14  let result3 = buildName("Bob", "Adams");   //   ah, just right 

2.3 剩余参数

关于剩余参数其本质就是ES6的收集(res)语法,使用"..."将多余的参数收集,但是TypeScript转换到ES5的js代码时还是需要使用arguments来实现,毕竟ES5版本中还没有收集(res)语法。详细可以了解 ES6入门一:块级作用域(let&const)、spread展开、rest收集

 1   function   buildName(firstName: string, ...restOfName: string[]) {
  2     return  firstName + " " + restOfName.join(" " );
  3   }
  4  
 5  let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

但是需要注意,收集语法产生的数据必然是数组,所以必须使用数组类型。

 三、TypeScript函数的this与箭头函数

关于this指向在JavaScript中一直是比较容易被它击晕的一个知识点,不要担心,我这里有一篇博客包治百病: JavaScript中的this指向规则

当然ES6的相关语法产生的this指向规则变化这里也有: ES6入门五:箭头函数、函数与ES6新语法

当然好不了严格模式的this指向问题: JavaScript严格模式

TypeScript并不改变JavaScript的this指向规则,而是在IDE中提供了更友好的警告提示,这个功能需要在tsconfig.json中通过"noImplicitThis": true开启。我们知道在JavaScript中this指向规则是比较复杂的,而TypeScript也根据这些规则做出了相应的调整,这里关于TypeScript函数的this指向其实就是了解"noImplicitThis"给我们的提示规则是什么?

3.1 TypeScript对象返回函数中的this会警告提示:

  1  let obj =  {
   2    strs : ["aaa","bbb","ccc","ddd" ],
   3    fun: function  (){
   4       return   function () {  //  这里会提示this出错,因为在严格模式下this可能为undefined,在TypeScript中IDE识别this类型为any,所以被认为可能出现undefined情况 
  5        let index = Math.floor(Math.random() *  this  .strs.length);
   6         return   this  .strs[index];
   7       }
   8     }
   9   }
  10   var  fun =  obj.fun();
  11  console.log(fun());

 这个问题可以使用箭头函数来解决:

  1  let obj =  {
   2    strs : ["aaa","bbb","ccc","ddd" ],
   3    fun: function  (){
   4       return  () => {  //  通过箭头函数解决 
  5        let index = Math.floor(Math.random() *  this  .strs.length);
   6         return   this  .strs[index];
   7       }
   8     }
   9   }
  10   var  fun =  obj.fun();
  11  console.log(fun());

3.2 this作为函数参数,不会出现错误提示,这一点需要注意,因为在原生JavaScritp种这种写法会直接出现语法错误。例如示例中这样写:

 1   function  f( this : void ){ //  这里你可以给形参任意TypeScript类型都不会报错 
 2       //  很遗憾这里并不会报错 
 3  }

这里有几方面的原因,严格模式下函数只执行内部this都是指向undefined,如果函数被对象调用this必然也就指向调用函数的对象。更关键的是被写在形参内的this根本就不会被TypeScript编译到原生js代码中,这里不报错其实是TypeScript将这个低级的错误帮你自动处理了,所以就静默了这个错误提示。

关于this作为参数在TypeScript中还有另一个功能,就是帮助函数维持this指向,例如官方这个示例:

  1   interface Card {
   2       suit: string;
   3       card: number;
   4   }
   5   interface Deck {
   6       suits: string[];
   7       cards: number[];
   8      createCardPicker( this : Deck): () =>  Card;
   9   }
  10  let deck: Deck =  {
  11      suits: ["hearts", "spades", "clubs", "diamonds" ],
  12      cards: Array(52 ),
  13       //   NOTE: The function now explicitly specifies that its callee must be of type Deck 
 14      createCardPicker:  function ( this  : Deck) {
  15           return  () =>  {
  16              let pickedCard = Math.floor(Math.random() * 52 );
  17              let pickedSuit = Math.floor(pickedCard / 13 );
  18  
 19               return  {suit:  this .suits[pickedSuit], card: pickedCard % 13 };
  20           }
  21       }
  22   }
  23  
 24  let cardPicker =  deck.createCardPicker();
  25  let pickedCard =  cardPicker();
  26  
 27  alert("card: " + pickedCard.card + " of " + pickedCard.suit);

上面这段代码中14行的createCardPicker: function(this: Deck){}被编译成了这样:

 1  createCardPicker:  function   () {
  2           var  _this =  this  ;
  3  }

上面这种代码是我们常用维持this指向的手段,在定义接口时常见的代码,在TypeScript中它使用this作为参数的方式来实现,这样的处理方式可以非常明显的看到this指向了对象自身,并且如果这个方法被赋值给其他对象变量时同样会静默这个this参数的错误,而其他对象在TypeScript严格的变量类型语法中也可能获取这个方法作为自身参数。

3.3 this在回调函数中如何维持this指向?下面是将官方文档代码补全的示例:

  1   interface UIElement {
   2    addClickListener(onclick: ( this :  void , e: Event) =>  void ):  void  ;
   3   }
   4  
  5   class Handler {
   6     info: string;
   7     constructor(infoStr:string){
   8       this .info =  infoStr;
   9     }
  10    onClickGood = (e: Event) => { //  通过箭头函数来保持函数内部this不变 
 11         //   can't use this here because it's of type void! 
 12        console.log( this ); //  指向Handler的实例对象 
 13        console.log( this .info); //  info 
 14        console.log('clicked!' );
  15     }
  16   }
  17  let h =  new  Handler('info' );
  18   class uiElementClass implements UIElement{
  19    addClickListener(onclick: ( this :  void , e: Event) =>  void ):  void  {
  20      onclick( new  Event('event' ));
  21     }
  22   }
  23  let uiElement:uiElementClass =  new   uiElementClass();
  24  uiElement.addClickListener(h.onClickGood);

 四、TypeScript函数重载

 关于TypeScript函数我想了好久就是不知道怎么解析这个东西,照着示例套吧,我也只能复制官方代码放这里了。

  1  let suits = ["hearts", "spades", "clubs", "diamonds" ];
   2  
  3   function   pickCard(x: {suit: string; card: number; }[]): number;
   4   function   pickCard(x: number): {suit: string; card: number; };
   5   function   pickCard(x:any): any {
   6       //   Check to see if we're working with an object/array 
  7       //   if so, they gave us the deck and we'll pick the card 
  8       if  ( typeof  x == "object" ) {
   9          let pickedCard = Math.floor(Math.random() *  x.length);
  10           return   pickedCard;
  11       }
  12       //   Otherwise just let them pick the card 
 13       else   if  ( typeof  x == "number" ) {
  14          let pickedSuit = Math.floor(x / 13 );
  15           return  { suit: suits[pickedSuit], card: x % 13  };
  16       }
  17   }
  18  
 19  let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4  }];
  20  let pickedCard1 =  myDeck[pickCard(myDeck)];
  21  alert("card: " + pickedCard1.card + " of " +  pickedCard1.suit);
  22  
 23  let pickedCard2 = pickCard(15 );
  24  alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

查看更多关于TypeScript入门三:TypeScript函数类型的详细内容...

  阅读:57次