函数中的类型注解
函数可以指定每个参数和返回值的类型:
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function (x: number, y: number): number {
return x + y;
};
当省略返回值的类型注解,Typescript 会自动根据返回的值进行类型推断。
函数类型
像其他变量的注解一样,也可以对一个变量标注为函数类型,格式为 (a: number, b:number) => number, 如下:
let myAdd: (x: number, y: number) => number = function (
x: number,
y: number
): number {
return x + y;
};
注意 x 和 y 只是提供占位功能,可以任意取名
类型推断
可以只写等式一边的类型注解,其余一边 Typescript 会自动根据语言环境自动进行类型推断:
// The parameters 'x' and 'y' have the type number
let myAdd = function (x: number, y: number): number {
return x + y;
};
// myAdd has the full function type
let myAdd2: (baseValue: number, increment: number) => number = function (x, y) {
return x + y;
};
可选和默认参数
在 Typescript 中函数的参数默认是都是必须的,所以在函数调用时传递参数的数量必须和声明时要相同:
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
Expected 2 arguments, but got 1.
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
Expected 2 arguments, but got 3.
let result3 = buildName("Bob", "Adams"); // ah, just right
在 JavaScript 中,函数的每个参数都是可选的,用户可以根据情况传递,没有传参的值默认为 undefined。而在 TypeScript 中,要想让一个参数可选,可以把类型注解改为 ?: :
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
Expected 1-2 arguments, but got 3.
let result3 = buildName("Bob", "Adams"); // ah, just right
注意的是,可选参数需要跟在必录参数后面。另外,我们可以为一个参数提供默认值,在用户没传或者传 undefined 使用它:
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith"
let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
Expected 1-2 arguments, but got 3.
let result4 = buildName("Bob", "Adams"); // ah, just right
跟随在必录参数后面的可选参数和默认参数可以看成是等价的:
function buildName(firstName: string, lastName?: string) {
// ...
}
等于:
function buildName(firstName: string, lastName = "Smith") {
// ...
}
和可选参数不一样的是,默认参数可以在必录参数前面出现。这个时候需要使用默认值,必须显示传递 undefiend 值:
function buildName(firstName = "Will", lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error, too few parameters
Expected 2 arguments, but got 1.
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
Expected 2 arguments, but got 3.
let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams"
let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams"
剩余参数
和 ES6 中的剩余参数类似,用 ... 表示剩余参数,它可以看出把所有的可选参数都放进一个数组:
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
// employeeName will be "Joseph Samuel Lucas MacKinzie"
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
同时支持函数类型注解和声明:
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
函数重载
有一些函数的参数类型可以是多种类型的,并且返回类型也可以是不确定的:
let suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: any): 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);
上面函数如果传入一个对象,则返回一个 number。如果传入一个数字,则返回卡片对象。那在 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): 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);
在函数调用时, TypeScript 会从重载函数列表第一个开始进行类型匹配,如果参数匹配成功,就会根据这个声明进行类型检查。
注意的是,函数重载列表最后一个声明不会进行类型匹配,所以上面的列表如果参数不匹配前面2钟话,就会抛出异常