Function types in typeScript

Table of contents

1. Function declaration

2. Function expression

3. Define the shape of the function with the interface

4. Optional parameters

5. Parameter default value

 6. Remaining parameters

7. Overload


Functions are the foundation of JavaScript applications. It helps you implement abstraction layers, mock classes, information hiding and modules. In TypeScript, although classes, namespaces, and modules are supported, functions are still the main place to define behavior. TypeScript adds extra functionality to JavaScript functions to make it easier for us to use.

1. Function declaration

In JavaScript, there are two common ways to define functions - Function Declaration (Function Declaration) and Function Expression (Function Expression) :

// 函数声明(Function Declaration)
function sum(x, y) {
    return x + y;
}

// 函数表达式(Function Expression)
let mySum = function (x, y) {
    return x + y;
};

A function has input and output. To constrain it in TypeScript, both input and output need to be considered. The type definition of the function declaration is relatively simple:

function sum(x: number, y: number): number {
    return x + y;
}

We can add types to each parameter before adding the return type to the function itself. TypeScript can automatically infer the return type from the return statement, so we usually omit it.

Function type consists of two parts: parameter type and return value type .

As long as the parameter types match, it is considered a valid function type, regardless of whether the parameter names are correct.

The second part is the return value type. For return values, we use the ( => ) symbol before the function and the return type to make it clear. The return value type is a necessary part of the function type. If the function does not return any value, you must also specify the return value type as void instead of leaving it blank .

2. Function expression

If we were to write a definition of a function expression (Function Expression) now, it might be written like this:

let mySum = function (x: number, y: number): number {
    return x + y;
};

This can be compiled, but in fact, the above code only defines the type of the anonymous function on the right side of the equal sign, while the one on the left side of the equal sign is  mySuminferred by the type inference of the assignment operation. If we need to manually  mySum add the type, it should be like this:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

Be careful not to confuse what's in TypeScript  => with what's in ES6  =>.

In the type definition of TypeScript, => it is used to represent the definition of a function. The left side is the input type, which needs to be enclosed in parentheses, and the right side is the output type.

In ES6, => it is called the arrow function, which is widely used. You can refer to the arrow function in ES6.

3. Define the shape of the function with the interface

We can also use interfaces to define the shape a function needs to conform to:

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1;
}

When using the method of function expression|interface to define a function, the type restriction on the left side of the equal sign can ensure that the number of parameters, parameter types, and return value types will not change when assigning a value to the function name in the future.

4. Optional parameters

Generally speaking, it is not allowed to enter extra (or less than required) parameters in the function. So how to define optional parameters?

Similar to optional properties in interfaces, we  ? denote optional parameters with:

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

Note that optional parameters must follow required parameters . In other words, optional parameters are not allowed to follow required parameters. Otherwise, the following error will be reported:

index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter。

5. Parameter default value

In ES6, we allow default values ​​to be added to function parameters, and TypeScript will recognize parameters with default values ​​as optional parameters :

function buildName(firstName: string, lastName: string = 'Cat') {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

At this time, it is not restricted by "optional parameters must be followed by required parameters".

 6. Remaining parameters

In ES6, you can use  ...rest the method to get the remaining parameters (rest parameters) in the function:

function push(array, ...items) {
    items.forEach(function(item) {
        array.push(item);
    });
}

let a: any[] = [];
push(a, 1, 2, 3);

 In fact, items is an array. So we can define it with the type of the array:

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}

let a = [];
push(a, 1, 2, 3);

Note that the rest parameter can only be the last parameter. 

7. Overload

Overloading allows a function to treat different numbers or types of arguments differently.

For example, we need to implement a function  that  outputs a reversed number when  reversea number is input  , and outputs  a reversed string when  a string  is inputted .123321'hello''olleh'

Using union types, we can do this:

function reverse(x: number | string): number | string | void {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

However, this has a disadvantage, that is, it cannot be expressed accurately. When the input is a number, the output should also be a number, and when the input is a string, the output should also be a string.

At this point, we can use overloading to define multiple  reverse function types:

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

 In the above example, we repeatedly defined the function multiple times  reverse, the first few times were function definitions, and the last time was function implementation. In the editor's code hints, the first two hints can be seen correctly. If you only look at my document, you can't see the difference, but if you type it, you can see the difference. (more precise definition function)

Note that TypeScript will give priority to matching from the first function definition, so if multiple function definitions have inclusion relationships, you need to write the precise definition first.

Guess you like

Origin blog.csdn.net/qq_57423665/article/details/130590700