typescript学习-函数

函数

函数类型

1
2
3
4
function add(x: number, y: number): number {
// 表示: add有两个形参,都是number类型,且返回值也是number类型
return x + y
}

完整函数类型

1
2
3
4
let myAdd: (x:number, y:number) => number = 
function(x: number, y: number): number {
return x + y
}

推断类型

即等式右侧的函数形参没有类型也能识别。这叫做“按上下文归类”,是类型推论的一种。

1
2
3
4
5
let myAdd: (baseValue: number, increment: number) => number =
function(x, y) {
// 这里x、y并没有限定类型
return x + y;
};

可选参数和默认参数

默认参数

1
2
3
4
5
6
7
8
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

可选参数

1
2
3
4
5
6
7
8
9
10
11
12
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

默认值

1
2
3
4
5
6
7
8
9
10
function buildName(firstName: string, lastName = "Smith") {
// 这里设置了lastName的默认值是smith
// 当没有传入时或者传入undefined时会默认为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
let result4 = buildName("Bob", "Adams"); // ah, just right

注意:带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入undefined值来获得默认值。

剩余参数

有时候想操作多个参数,或者并不知道会有多少参数传递进来。

1
2
3
4
function buildName(firstName: string, ...restOfName: string[]) {
return `${firstName} ${restOfName.join('')}`
}
let employeeName = buildName('joseph','samuel', 'lucas', 'mackinzie')

剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号(...)后面给定的名字,你可以在函数体内使用这个数组。

this

使用this时需要确定上下文,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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(); // 在全局环境下调用,this指向window,导致报错
let pickedCard = cardPicker();

alert("card: " + pickedCard.card + " of " + pickedCard.suit);

解决第一步:

1
2
3
4
5
6
7
8
9
10
createCardPicker: function() {
// 替换deck里的函数为箭头函数
// 箭头函数this指向定义时候的this值
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);

return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}

这时会爆warn,指出this类型是any。

解决第二部:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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) {
// 👆这里加了this的类型
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);

return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}

现在TypeScript知道createCardPicker期望在某个Deck对象上调用。 也就是说thisDeck类型的,而非any,因此--noImplicitThis不会报错了。

重载

JavaScript本身是个动态语言。 JavaScript里函数根据传入不同的参数而返回不同类型的数据是很常见的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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类型判断
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 };
}
}

在函数类型里如何表示?

为同一个函数提供多个函数类型定义来进行函数重载。 编译器会根据这个列表去处理函数的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 };
}
}

为了让编译器能够选择正确的检查类型,它与JavaScript里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。

因此,在定义重载的时候,一定要把最精确的定义放在最前面。

感谢您的阅读。 🙏