声明:本学习系列参考了TypeScript3.3英文版官网教程
函数
typescript对标准的js函数增加了一些新的特性来让它更容易使用,typescript支持匿名函数和命名函数函数
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
1、完整的函数类型
完整的函数类型包括两个部分:参数列表和返回值类型。返回值类型使用=>
表示。
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number { return x + y; };
参数名称不一定要相同,只要它的顺序和类型匹配即可上例也可以改写成
let myAdd: (baseValue: number, increment: number) => number =
function(x: number, y: number): number { return x + y; };
1.1、推断类型
如果你只在等式的一边指定来函数类型,为另一边没有指定,typescript会自动推断出你函数类型。
// myAdd has the full function type
let myAdd = function(x: number, y: number): number { return x + y; };
// The parameters 'x' and 'y' have the type number
let myAdd: (baseValue: number, increment: number) => number =
function(x, y) { return x + y; };
2、可选参数个默认参数
在js中每一个参数都是可选的,如果不传入就默认为undefined
,但是在typescript中每一个参数都假设是必须的,换句话说就是所给的实参必须匹配函数的形参列表,不能多也不能少。
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
我们可以在参数名后添加?
来设置可选参数,可选参数必须放在必传参数的后面。
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // works correctly now
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
我们也可以使用默认参数,如果没有传入值或者传入值是undefined
就会使用默认参数,默认参数可以放在参数列表的任何地方,如果放在了必传参数的前面,则必须显示的传入undefined
。
function buildName(firstName = "Will", lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams"
let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams"
3、剩余参数
如果你想传入多个值到函数里,可以使用剩余参数,它会把你传入的剩余参数保存在一个数组里,使用...
来定义一个剩余参数。
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
4、this
4.1this的使用
在js怎样使用this
就好像一场成年礼
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
return 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();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
这段代码会报错,因为调用函数时的this
是指向window的而不是deck。可以使用es6的箭头函数来修复这个问题
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 here
return () => {
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);
虽然我们使用箭头函数解决了这个问题,但我们仍然不知道this
的具体类型,如果你在编译器中传入来--noImplicitThis
标志时,它将会指出this.suits[pickedSuit]
中this
的类型是any
,为了修复这个问题我们可以显示的传入一个this
参数作为第一个参数。
interface Card {
suit: string;
card: number;
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;
}
let deck: Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
// NOTE: The function now explicitly specifies that its callee must be of type Deck
createCardPicker: function(this: Deck) {
return () => {
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);
现在编译器知道this
是Deck
的类型了,所以--noImplicitThis
就不会报错了。
4.2回调函数中的this
你可能在回调函数中使用this
出错,例如如果一个库的作者指定了回调中this
的类型
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
这里作者把回调的this
设置为void
,意味着函数中不需要使用this
,如果你在回调中传入了不是void
类型的this
,编译器将会报错。
class Handler {
info: string;
onClickBad(this: Handler, e: Event) {
// oops, used this here. using this callback would crash at runtime
this.info = e.message;
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!
5、函数重载
在js中函数通过传入不同的参数来返回不同类型的对象是很常见的事情,在typescript里可以使用函数重载来实现,对同一个函数使用多个函数类型来表示重载,编译器会查找重载列表,直到找到第一个匹配的为止,因此要把最精确的放在前面。
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 card
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else 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)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
注意这里的function pickCard(x): any
并不是重载列表的一部分,这里只有两个重载,一个接受对象,一个接受数字。