为函数定义类型
let myAdd = function(x: number, y: number): number { return x + y; };//myAdd 是一个函数类型,有两个参数分别是x,y并且都为数值类型,返回值也是数值类型
书写完整的函数类型
let myAdd: (x: number, y: number) => number =function(x: number, y: number): number { return x + y; };//myAdd 是一个函数类型,有两个参数分别是x,y并且都为数值类型,返回值也是数值类型这是一个完整的类型
函数类型包含两部分,参数类型和返回值类型。只要参数类型匹配,并不在乎参数名是否一致,返回类型也不许和声明的类型一致。
推断类型:在typescript中 ,编译器会自动识别类型(按上下文归类,是类型推论的一种)
可选参数和默认参数
function buildName(firstName: string, lastName?: string) {if (lastName)return firstName + " " + lastName;elsereturn firstName;}let result1 = buildName("Bob"); // works correctly nowlet result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameterslet result3 = buildName("Bob", "Adams"); // ah, just rightbuildName有两个参数firstName字符串类型必传,lastName属性后有一个?代表是可选类型,可以不传,如果传递必须是字符串类型,另外可选参数必须在必须参数后面。并且可以设置参数的默认值;'function buildName(firstName: string ='aaa', lastName?: string) {if (lastName)return firstName + " " + lastName;elsereturn firstName;}
在所有必须参数后面带默认初始化的参数都是可选的,可以省略不全,也就是说可选参数与末尾的默认参数共享参数类型。
function buildName(firstName: string, lastName?: string) {} 等同于function buildName(firstName: string, lastName = "Smith") {}
如果带默认值的参数放在必须参数值的前面,则函数要明确的传入undefined值来获得默认值。
function buildName(firstName = "Will", lastName: string) {return firstName + " " + lastName;}let result4 = buildName(undefined, "Adams"); //error
剩余参数
必须参数,默认参数,可选参数都有共同点,他表示一个参数,如果你不知道后边有多少个参数可以利用剩余参数来实现
function buildName(firstName: string, ...restOfName: string[]) {return firstName + " " + restOfName.join(" ");}let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");buildName函数第一个参数为string,第二个参数利用剩余参数,转化为数组,
this和箭头函数
普通函数在运行时才知道this指向,使用箭头函数,在函数被返回时就绑好正确的this
let deck = {suits: ["hearts", "spades", "clubs", "diamonds"],cards: Array(52),createCardPicker: function() {// NOTE: the line below is now an arrow function, allowing us to capture 'this' right herereturn () => {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return {suit: this.suits[pickedSuit], card: pickedCard % 13};}}}let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();alert("card: " + pickedCard.card + " of " + pickedCard.suit);
注意:如果createCardPicker返回的是一个普通函数,且 编译器做了 noImplicitThis 值为true 是,会提示this 类型为any
let deck = {suits: ["hearts", "spades", "clubs", "diamonds"],cards: Array(52),createCardPicker: function() {// NOTE: the line below is now an arrow function, allowing us to capture 'this' right herereturn function() {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return {suit: this.suits[pickedSuit], card: pickedCard % 13};}}}let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();// this.suits[pickedSuit] 报错显示this 是一个any类型。
this参数
不幸的是,this.suits[pickedSuit]的类型依旧为any。 这是因为 this来自对象字面量里的函数表达式。 修改的方法是,提供一个显式的 this参数。 this参数是个假的参数,它出现在参数列表的最前面:
function f(this: void) {}
所以上面的例子可以这样改
let deck = {suits: ["hearts", "spades", "clubs", "diamonds"],cards: Array(52),createCardPicker: function(this: Deck) { //此处显示的指出了this指向为Deck,也可以不写类型自动推导// NOTE: the line below is now an arrow function, allowing us to capture 'this' right herereturn () => {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return {suit: this.suits[pickedSuit], card: pickedCard % 13};}}}let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();alert("card: " + pickedCard.card + " of " + pickedCard.suit);也可以将deck.createCardPicker的返回函数修改为如下:return function(this:Deck) { 返回普通函数,显示指向thislet pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return { suit: this.suits[pickedSuit], card: pickedCard % 13 };}
this参数在回调函数里
当一个函数传递到另一个函数被调用时,他们会当成一个普通函数,this为undefined。我们稍作改动通过this函数避免错误,首先要指定this类型
interface UIElement {addClickListener(onclick: (this: void, e: Event) => void): void;}this:void 表示addClickListener期望onclick 是一个不需要此类型得函数
下面为调用代码
interface UIElement {addClickListener(onclick: (this: void, e: Error) => void): void;}class Handler {info: string = '';onClickBad(this: Handler, e: Error) {// oops, used this here. using this callback would crash at runtimethis.info = e.message;}}let h = new Handler();let uiElement: UIElement = {addClickListener: (onclick: (this: void, e: Error) => void): void => {// do something}}uiElement.addClickListener(h.onClickBad); // error! onClickBad指定this 必须在Handler类中使用
当我们指定this类型时候,显示声明得onClickBad就必须在Hadnler,这是因为typescript会检测到指定类型
我们下面添加另一个方法让this为void
interface UIElement {addClickListener(onclick: (this: void, e: Error) => void): void;}class Handler {info: string = '';onClickBad(this: Handler, e: Error) {// oops, used this here. using this callback would crash at runtimethis.info = e.message;}onClickGood(this: void, e: Error){this.info = e.message; //error thsi 指向问题}}let h = new Handler();let uiElement: UIElement = {addClickListener: (onclick: (this: void, e: Error) => void): void => {// do something}}uiElement.addClickListener(h.onClickBad); // error! onClickBad指定this 必须在Handler类中使用uiElement.addClickListener(h.onClickGood); // ok!
但是,this.info就不可用了因为它不指向Hander,如果都需要那么将onClickGood改成箭头函数即可。因为箭头函数不会捕获this,所以我们总是可以把他们传给期望得this:void 函数,缺点就是每个Handler 对象都会创建一个箭头函数,另一方面,方法只会被创建一次,添加到 Handler的原型链上。 它们在不同 Handler对象间是共享的。
class Handler {info: string = '';onClickBad(this: Handler, e: Error) {// oops, used this here. using this callback would crash at runtimethis.info = e.message;}onClickGood = (e: Error) => {this.info = e.message; //不报错}}let h = new Handler();let uiElement: UIElement = {addClickListener: (onclick: (this: void, e: Error) => void): void => {// do something}}uiElement.addClickListener(h.onClickGood); //ok
重载:方法名相同但是参数和返回值不同
方法是为同一个函数提供多个函数类型定义来进行函数重载。传入不同参数就会得到不同的值。 编译器会根据这个列表去处理函数的调用。为了让编译器能够正确的检查类型,在查找列表的时候,一定要把最精确得定义放在最前面
let suits = ["hearts", "spades", "clubs", "diamonds"];function pickCard(x: {suit: string; card: number; }[]): number;function pickCard(x: number): {suit: string; card: number; };function pickCard(x): any {// Check to see if we're working with an object/array// if so, they gave us the deck and we'll pick the cardif (typeof x == "object") {let pickedCard = Math.floor(Math.random() * x.length);return pickedCard;}// Otherwise just let them pick the cardelse if (typeof x == "number") {let pickedSuit = Math.floor(x / 13);return { suit: suits[pickedSuit], card: x % 13 };}}let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];let pickedCard1 = myDeck[pickCard(myDeck)];console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);let pickedCard2 = pickCard(15);console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
注意:function pickCard(x):any 并不是重载列表的一部分,这里有两个重载,一个接收对象,另一个接收数字,以其他参数调用会产生错误。
知识总结:
1.在TypeScript中可以为函数定义类型let myadd:(x:number,y:number)=>number = (x:number,y:number):number {return x + y;}其中 (x:number,y:number)=>number 这就是为函数定义的的类型,只需要参数类型匹配即可2.在TypeScript编译器中,编译器会自动识别出类型,这叫做按上下文归类,是类型推论中得一种3.在TypeScript参数有可选和默认参数,如果定义得函数中某个参数是可选的(也就是可以不传递),默认参数也可以不传递,但是必须占位,并且可选参数一定要在必传参数得后面.function buildName(firstName: string, lastName?: string) {return firstName + " " + lastName;}lastName后面跟一个?就代表是可选包参数function buildName(firstName: string, lastName = "Smith") {return firstName + " " + lastName;}lastName = "Smith" 是默认参数,他也是可选得。4.剩余参数,如果函数得参数不固定可以用 "...arg" 将他们变成一个数组5.this 参数 我们可以显示得指出this 他是一个假参数,只是告诉编译器this需要在什么地方能够使用,有时候this可能是一个any类型,如果你给编译器设置了--noImplicitThis标记。 它会指出 否个函数里的this的类型为any。6.重载:是为一个函数提供多个函数类型定义。另外只是类型重载,并不是函数重载,比如上面的例子,是两个重载而不是三个
