Functions are the fundamental building block of any applications in JavaScript.

  1. // Named function
  2. function add(x, y) {
  3. return x + y;
  4. }
  5. // Anonymous function
  6. let myAdd = function(x, y) { return x + y; };
  7. // caputure variables (via scope)
  8. let z = 100;
  9. function addToZ(x, y) {
  10. return x + y + z;
  11. }

Function Types

Writting the function type

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

Inferring the types

“contextual typing”, a form of type inference (按上下文归类, 类型推断的一种)
就是 ts 会自己推导类型不用你乱七八糟写一堆

  1. // myAdd has the full function type
  2. let myAdd = function(x: number, y: number): number { return x + y; };
  3. // The parameters 'x' and 'y' have the type number
  4. let myAdd: (baseValue: number, increment: number) => number =
  5. function(x, y) { return x + y; };

Optional and Default Parameters

ts 会严格比较函数参数个数

  1. function buildName(firstName: string, lastName: string) {
  2. return firstName + " " + lastName;
  3. }
  4. let result1 = buildName("Bob"); // error, too few parameters
  5. let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
  6. let result3 = buildName("Bob", "Adams"); // ah, just right

可以用 ? 实现可选参数, 必须放在 required parameters 后面

  1. function buildName(firstName: string, lastName?: string) {
  2. if (lastName)
  3. return firstName + " " + lastName;
  4. else
  5. return firstName;
  6. }
  7. let result1 = buildName("Bob"); // works correctly now
  8. let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
  9. let result3 = buildName("Bob", "Adams"); // ah, just right

默认参数, 不一定要放在 required parameters 后面

  1. function buildName(firstName: string, lastName = "Smith") {
  2. return firstName + " " + lastName;
  3. }
  4. let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"
  5. let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith"
  6. let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
  7. let result4 = buildName("Bob", "Adams"); // ah, just right
  8. // 在 required parameters 前面
  9. function buildName(firstName = "Will", lastName: string) {
  10. return firstName + " " + lastName;
  11. }
  12. let result1 = buildName("Bob"); // error, too few parameters
  13. let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
  14. let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams"
  15. let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams"

Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. This means optional parameters and trailing default parameters will share commonality in their types.

  1. function buildName(firstName: string, lastName?: string) {
  2. // ...
  3. }
  4. function buildName(firstName: string, lastName = "Smith") {
  5. // ...
  6. }
  7. // 所以上面两个函数的类型是一样的
  8. // 都是 (firstName: string, lastName?: string) => string

Rest Parameters

reuqired, optional, default parameters 都是按个来算的
批量的参数就可以用 rest parameters (也可以直接使用 arguments )

Rest parameters are treated as a boundless number of optional parameters.

  1. function buildName(firstName: string, ...restOfName: string[]) {
  2. return firstName + " " + restOfName.join(" ");
  3. }
  4. let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

this

In JavaScript, this is a variable that’s set when a function is called
Understanding JavaScript Function Invocation and “this”

this and arrow functions

Arrow functions capture the this where the function is created rather than where it is invoked

箭头函数的 this 是定义时所在的对象, 不是使用时所在的对象

this parameters

即便用箭头函数保证了 this 正确, 但是 ts 对下面的 this.suits[pickedSuit] 也还是不能正确推导类型
这是因为此时箭头函数的 this 取决于 createCardPicker 的 this, 然而 createCardPicker this 也还不知道哪里来呢

  1. let deck = {
  2. suits: ["hearts", "spades", "clubs", "diamonds"],
  3. cards: Array(52),
  4. createCardPicker: function() {
  5. // NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
  6. return () => {
  7. let pickedCard = Math.floor(Math.random() * 52);
  8. let pickedSuit = Math.floor(pickedCard / 13);
  9. return {suit: this.suits[pickedSuit], card: pickedCard % 13};
  10. }
  11. }
  12. }
  13. let cardPicker = deck.createCardPicker();
  14. let pickedCard = cardPicker();
  15. alert("card: " + pickedCard.card + " of " + pickedCard.suit);

所以可以使用 this parameter, 把接口定义出来, 给 ts 一个提示:

  1. interface Card {
  2. suit: string;
  3. card: number;
  4. }
  5. interface Deck {
  6. suits: string[];
  7. cards: number[];
  8. createCardPicker(this: Deck): () => Card;
  9. }
  10. let deck: Deck = {
  11. suits: ["hearts", "spades", "clubs", "diamonds"],
  12. cards: Array(52),
  13. // NOTE: The function now explicitly specifies that its callee must be of type Deck
  14. createCardPicker: function(this: Deck) {
  15. return () => {
  16. let pickedCard = Math.floor(Math.random() * 52);
  17. let pickedSuit = Math.floor(pickedCard / 13);
  18. return {suit: this.suits[pickedSuit], card: pickedCard % 13};
  19. }
  20. }
  21. }
  22. let cardPicker = deck.createCardPicker();
  23. let pickedCard = cardPicker();
  24. alert("card: " + pickedCard.card + " of " + pickedCard.suit);

Overloads

The answer is to supply multiple function types for the same function as a list of overloads

就是写多个 fucntion types, 只写一个函数实现 (感觉这样的重载看起来有点奇怪…)
声明的 function types 组成一个 overload list
在 overload list 从上到下匹配, 匹配到第一个成功的就不理后面的了, 所以越精确的写在越前面

  1. let suits = ["hearts", "spades", "clubs", "diamonds"];
  2. function pickCard(x: {suit: string; card: number; }[]): number;
  3. function pickCard(x: number): {suit: string; card: number; };
  4. function pickCard(x): any {
  5. // Check to see if we're working with an object/array
  6. // if so, they gave us the deck and we'll pick the card
  7. if (typeof x == "object") {
  8. let pickedCard = Math.floor(Math.random() * x.length);
  9. return pickedCard;
  10. }
  11. // Otherwise just let them pick the card
  12. else if (typeof x == "number") {
  13. let pickedSuit = Math.floor(x / 13);
  14. return { suit: suits[pickedSuit], card: x % 13 };
  15. }
  16. }
  17. let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
  18. let pickedCard1 = myDeck[pickCard(myDeck)];
  19. alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
  20. let pickedCard2 = pickCard(15);
  21. alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);