Functions
Function Declaration
A function declaration introduces a function, including its name, parameter list, return type, and function body.
Example of a simple function with two string - typed parameters and a string return type:
function add(x: string, y: string): string {
let z: string = `${x} ${y}`;
return z;
}
In a function declaration, each parameter must be type - annotated. If a parameter is optional, it can be omitted when calling the function. The last parameter of a function can be a rest parameter.
Optional Parameters
Optional parameters can be in the format of name?: Type.
function hello(name?: string) {
if (name == undefined) {
console.log('Hello!');
} else {
console.log(`Hello, ${name}!`);
}
}
Another form of optional parameter is setting a default value for the parameter. If the parameter is omitted in a function call, its default value will be used as the argument.
function multiply(n: number, coeff: number = 2): number {
return n * coeff;
}
multiply(2); // Returns 2*2
multiply(2, 3); // Returns 2*3
Rest Parameters
The last parameter of a function can be a rest parameter in the format of... restArgs. Rest parameters allow a function to receive an array of remaining arguments, enabling it to handle an indefinite number of input parameters.
function sum(...numbers: number[]): number {
let res = 0;
for (let n of numbers)
res += n;
return res;
}
sum(); // Returns 0
sum(1, 2, 3); // Returns 6
Return Type
If the return type of a function can be inferred from within the function body, the return type annotation can be omitted in the function declaration.
// Explicitly specifying the return type
function foo(): string { return 'foo'; }
// The return type is inferred as string
function goo() { return 'goo'; }
For functions that do not need to return a value, the return type can be explicitly specified as void or the annotation can be omitted. Such functions do not require a return statement.
Both of the following function declaration styles are valid:
function hi1() { console.log('hi'); }
function hi2(): void { console.log('hi'); }
Function Scope
Variables and other instances defined within a function can only be accessed within the function and cannot be accessed from outside.
If a variable defined within a function has the same name as an instance in an outer scope, the local variable within the function will shadow the outer definition.
Function Calls
A function is called to execute its body. The actual parameter values are assigned to the function's formal parameters.
Given the following function definition:
function join(x: string, y: string): string {
let z: string = `${x} ${y}`;
return z;
}
Calling this function requires two arguments of type string:
let x = join('hello', 'world');
console.log(x);
Function Types
Function types are commonly used to define callbacks:
type trigFunc = (x: number) => number // This is a function type
function do_action(f: trigFunc) {
f(3.141592653589); // Invoke the function
}
do_action(Math.sin); // Pass a function as an argument
Arrow Functions (Also Known as Lambda Functions)
Functions can be defined as arrow functions. For example:
let sum = (x: number, y: number): number => {
return x + y;
}
The return type of an arrow function can be omitted; when omitted, the return type is inferred from the function body.
Expressions can be specified as arrow functions to make the expression more concise. The following two expressions are equivalent:
let sum1 = (x: number, y: number) => { return x + y; }
let sum2 = (x: number, y: number) => x + y
Closures
A closure is composed of a function and the environment in which the function was declared. This environment includes any local variables within the scope at the time of the closure's creation.
In the following example, function f returns a closure that captures the count variable. Each time z is called, the value of count is retained and incremented.
function f(): () => number {
let count = 0;
let g = (): number => { count++; return count; };
return g;
}
let z = f();
z(); // Returns: 1
z(); // Returns: 2
Function Overloading
We can specify different ways to call a function through overloading. This is achieved by writing multiple function heads with the same name but different signatures for the same function, followed by the function implementation.
function foo(x: number): void; /* First function definition */
function foo(x: string): void; /* Second function definition */
function foo(x: number | string): void { /* Function implementation */
}
foo(123); // OK, uses the first definition
foo('aa'); // OK, uses the second definition
It is not allowed to have function overloads with the same name and parameter list; otherwise, a compilation error will occur.
Top comments (0)