TypeScript 基础 函数类型
// 给每个参数添加类型之后再为函数本身添加返回值类型。
// TypeScript 能够根据返回语句自动推断出返回值类型,因此我们通常省略它。
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
完整函数类型
函数类型包含两部分:参数类型和返回值类型。
当写出完整函数类型的时候,这两部分都是需要的。 我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。 这个名字只是为了增加可读性:
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; };
# 推断类型
// 如果在赋值语句的一边指定了类型但是另一边没有类型的话,TypeScript 编译器会自动识别出类型
let myAdd: (baseValue: number, increment: number) => number =
function(x, y) { return x + y; };
对于返回值,我们在函数和返回值类型之前使用( =>
) 符号,返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为 void
而不能留空。
函数的类型只是由参数类型和返回值组成的。 函数中使用的捕获变量不会体现在类型里。 实际上,这些变量是函数的隐藏状态并不是组成 API 的一部分。
可选参数和默认参数
传递给一个函数的参数个数必须与函数期望的参数个数一致
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
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"
剩余参数
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
this
JavaScript 里, 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);
上面的代码报错,因为 createCardPicker
返回的函数里的 this
被设置成了 window
而不是 deck
对象。因为我们只是独立的调用了 cardPicker()
。 顶级的非方法式调用会将 this
视为 window
。 (注意:在严格模式下, this
为 undefined
而不是 window
)。
箭头函数能保存函数创建时的 this
值,而不是调用时的值 :
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
// 注意:下面的这条线现在是一个箭头函数,允许我们在这里捕捉 this
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
如果你给编译器设置了 --noImplicitThis
标记。 它会指出 this.suits[pickedSuit]
里的 this
的类型为 any
。
this 参数
不幸的是, this.suits[pickedSuit]
的类型依旧为 any
。 这是因为 this
来自对象字面量里的函数表达式。 修改的方法是,提供一个显式的 this
参数。 this
参数是个假的参数,它出现在参数列表的最前面:
function f(this: void) {
// 确保‘ this’在这个独立函数中不可用
}
让我们往例子里添加一些接口, Card
和 Deck
,让类型重用能够变得清晰简单些:
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),
// 注意: 这个函数现在明确指定它的被调用方必须是 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);
现在 TypeScript 知道 createCardPicker
期望在某个 Deck
对象上调用。 也就是说 this
是 Deck
类型的,而非 any
,因此 --noImplicitThis
不会报错了。
函数重载
重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。
如果参数类型不同,则参数类型应设置为 any 。参数数量不同你可以将不同的参数设置为可选。
根据传入不同的参数而返回不同类型的数据
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 {
// 检查是否使用 object/array
// 如果是这样,他们给我们一副牌,我们来选牌
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// 否则就让他们自己选牌
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);
这样改变后,重载的 pickCard
函数在调用的时候会进行正确的类型检查。
为了让编译器能够选择正确的检查类型,它与 JavaScript 里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此, 在定义重载的时候,一定要把最精确的定义放在最前面 。
注意, function pickCard(x): any
并不是重载列表的一部分,因此这里只有两个重载:一个是接收对象另一个接收数字。 以其它参数调用 pickCard
会产生错误 。
小结
- 函数类型包含 参数类型 和 返回值类型 两部分
- 传递给一个函数的参数个数必须与函数期望的参数个数一致
- 使用
?
实现可选参数,可选参数必须跟在必须参数后面。 - 默认值当用户没有传递这个参数或传递的值是
undefined
时生效,如果带默认值的参数出现在必须参数前面,用户必须明确的传入undefined
值来获得默认值。 - JavaScript 里,
this
的值在函数被调用的时候才会指定。而 箭头函数 能保存函数创建时的this
值,而不是调用时的值 - 在定义重载的时候,一定要把最精确的定义放在最前面
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论