This is the 11th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

Learning function types

We’ve learned about type inference, type assertion, union types, type aliases, and so on.

Yes, I believe you have your own understanding of the TS type system.

The type system not only improves our development efficiency, but also enhances the maintainability of our code.

And bugs can be caught early in the build phase before the code goes live.

Let’s continue learning about function types in TS.

Type of function

Now, how are function types defined in TS?

JS code

function getName(firstName, lastName) {
    return firstName + ' ' + lastName;
}
Copy the code

TS code

We know that a function is divided into two parts: input and output. When we define a function type, we define both input and output types.

function getName(firstName: string, lastName: string) : string {
    return firstName + ' ' + lastName;
}

What is the type of the first argument, the second argument, and the return value
// At the same time, this variable will deduce the type from the return value of the function
let myName = getName('Alex'.'Zhang');

// If we call the function with one more argument, we will get an error because we defined two arguments and passed three here
// We should have 2 parameters, but we got 1 parameter
// let myName = getName('Alex', 'Zhang', 'P');
Copy the code

But sometimes we want the second argument to be optional

function getName(firstName: string, lastName? :string) : string {
    if(! lastName) {return firstName;
    }
    return firstName + ' ' + lastName;
}
Copy the code

Optional arguments have a second way of adding default values to them

function getName(firstName: string, lastName? :string = 'Wu') : string {
    if(! lastName) {return firstName;
    }
    return firstName + ' ' + lastName;
}
Copy the code

Exercise – Refine the following code blocks based on your knowledge of function types

type animalType = {
    name: string;
    weight: number;
};
const panda: animalType = {
    name: 'panda'.weight: 10
};
const animal = [panda, panda];
// Use declared types whenever possible to improve code reading
function foo(index: _____) :_____ {
    return animal[index];
}
foo(0);
Copy the code

The answer

// The first blank answer
number

// The second blank answer
animalType
Copy the code

parsing

The first blank is the parameter type of the function, according to the code

foo(0);
Copy the code

You can see that the parameter should be of type number.

The second blank is the return type of the function, which returns the 0 element of the array Animal. So the function returns a value of type

{
    name: string;
    weight: number;
}
Copy the code

Since the type alias animalType is already declared in the code block, it is more appropriate to use animalType to increase code readability.

Type inference – functions

Let’s continue with the previous example and look at the application of type inference to functions.

// The input and output types of the function are inferred to be any, so myName is of any type
function getName(firstName, lastName?) {
    if(! lastName) {return firstName;
    }
    return firstName + ' ' + lastName;
}
let myName = getName('Alex');

// Keep the input type, but do not add the output type? The output is inferred to a string, because the output of each branch of this function is inferred from the input to be a string, so the output is a string
function getName(firstName: string, lastName? :string) {
    if(! lastName) {return firstName;
    }
    return firstName + ' ' + lastName;
}
let myName = getName('Alex');

If instead of adding a type to the function input, we add a default value to the parameter input, then we can correctly infer that the output is of type string
function getName(firstName = 'Bob', lastName = 'Wu') {
    if(! lastName) {return firstName;
    }
    return firstName + ' ' + lastName;
}
let myName = getName('Alex');
Copy the code

Problem set – Strictly typed mode, variablesanimalIs of the type?

const animal = function() {
    return { name: 'panda'.weight: 10 };
}
Copy the code

A. any

B. () => { name: string; weight: number }

C. { name: string; weight: number }

Answer: B

parsing

Animal is assigned to a function, so animal is inferred to a specific function type.

  • A – anyNot a specific function type. So the mistake.
  • B – This option is a function type and the parameter and return value types of the function match those of the assignment function. Therefore, correct.
  • C – This option is an object type (the return value type of the function). So the mistake.

Data – Remaining parameters

In EcmaScript 6, you can… Rest way to define the rest parameters (REST parameters)

function bookList(list: string[], ...books: string[]) :string[] {
    books.forEach(item= > {
        list.push(item);
    });
    return books;
};

let list = bookList([], 'book1'.'book2'.'book3');
Copy the code

From the above code we can see that… Books is actually an array, so we define its type with string[]

Note:… The REST parameter can only be the last parameter. For rest parameters, seeRest parameters in ES6.

Function expressions vs function declarations

There are two ways to define functions in JS: function declarations and function expressions.

// Function declaration
function getName(firstName, lastName) {
    return firstName + lastName;
}
// Function expression
let getUsername = function (firstName, lastName) {
    return firstName + lastName;
}
// The input and output of this function expression are inferred to type any
Copy the code

Next, we define its input and output as strings using a type declaration, and then move the mouse over to see the corresponding type inference

let getUsername = function (firstName: string, lastName: string) :string {
    return firstName + lastName;
}

// During the call, the editor will ask what type of input parameter and output are
Copy the code

Can we define a variable without defining the following function type?

The answer is yes.

type GetUserNameFunc = (x: string, y: string) = > string;
let getUsername: GetUserNameFunc = function (firstName, lastName) {
    return firstName + lastName;
}

getUsername('Alex'.'Wu');
Copy the code

In ES6, arrows are used to indicate a function, while in TS, arrows indicate the type of a function

Problem set – Strictly typed mode, variablesgetAnimalA type of

const animal = [{ name: 'panda'.weight: 10 }];
type AnimalType = { name: string; weight: number; }
const getAnimal = function(index: number) :AnimalType {
    return animal[index];
}
Copy the code

A. AnimalType

B. (index: number) => AnimalType

C. (index: number) => number | string

D. number | string

Answer: B

parsing

The variable getAnimal is assigned to a function, so the variable getAnimal is inferred to the specific function type.

  • A – This optionanimalTypeA type is a defined type alias and is an object type. So the mistake.
  • B – This option is a function type, and the parameter and return structure types of the function match those of the assignment function. Therefore, correct.
  • C – This option is a function type, but the return value type of the function in this option is a union type. The union types are all basic data types. Does not match the return value type of the assignment function. So the mistake.
  • D – The union types of this option are all basic data types. So the mistake.

Arrow function

Let’s look at the definition of the arrow function type.

It is easy to define an arrow function by removing the function from the normal function and adding the arrow.

You need to distinguish between function type definitions in TS. We are defining a real function here, not a type.

This is similar to the use of the function type above.

let getUsername = (firstName: string.lastName: string) :string= > {
    return firstName + lastName;
}
Copy the code