TypeScript Functions Tutorial

In this TypeScript tutorial we learn how to group sections of our code into smaller, reusable units, with functions.

We learn how to define and invoke functions, how to add parameters and arguments, and how to return a value (and control) back from the function.

Lastly, we take a look at arrow functions (function expressions).

What is a function

Functions allow us to group sections of our code into a smaller, reusable unit.

As an example, let’s consider some simple logic.

Example:
// number to check
let num: number = 5

// if the number can be divided by two
// without a remainder, it's an even num
if (num % 2 == 0) {
  console.log(num, " is an even number")
} else {
  console.log(num, " is an odd number")
}

The example above will check if a number is even or odd.

Our application may require this evaluation multiple times throughout the code. We don’t want to repeat ourselves and retype this logic each time.

Instead, we want to separate the logic into a reusable unit that we can more easily use over and over, anywhere in our code.

How to create (define) a named function

A function consists of the following parts.

  • The function keyword.
  • A name.
  • A parameter list (optional).
  • A body with one or more statements.
  • A returned value (optional).

We call it a named function, because it has a name we can refer to when we invoke it.

Syntax:
function name(parameters: parameter_types): return_type {
  // one or more logic statements
  return value
}

This is known as a function definition and it can be simple or complex. Let’s start with the most basic function and add features as we need them.

Example:
function logger() {
  console.log("Hello World")
}

In the example above, we create a function called logger . All it does is execute the console.log() statement to log a message to the console.

note Even if we don’t include any parameters in the parameter list, we have to specify the open and close parentheses.

But, when we compile and run the script, nothing happens. This is because we’ve defined the function, but we haven’t used it yet.

How to use (invoke/call) a function

To use a function, we need to tell the compiler that we want the function to execute its code once. We do this by invoking the function, otherwise known as calling it.

To call a function we write its name, followed by the open and close parentheses of the parameter list. Because the call doesn’t have a closing curly brace, we also need to terminate the statement with a semicolon.

Syntax:
// definition
function name(parameters) {
  // function body
  return value
}

// call
name(arguments_for_parameters)

As an example, let’s use our simple logger function from the previous section.

Example:
// definition
function logger() {
  console.log("Hello World")
}

// invoke / call function
logger()

This time, when we compile and run the script, the words ‘Hello World’ are printed.

note Even though we don’t have any parameters, and therefore don’t need any arguments, we still need to add the parentheses in the both the definition and the call.

We can also call a function anywhere in the document, it doesn’t have to be below the function definition.

Example:
// invoke / call function
logger()

// definition
function logger() {
  console.log("Hello World")
}

// invoke / call function
logger()

How to add parameters to a function

At this point our logger function isn’t very useful, it only prints ‘Hello World’ to the console. We can change it so that the function prints any message we want.

A parameter is simply a temporary variable that we can use inside the body of the function. The compiler will replace every occurance of the parameter in the definition, with whatever we specify as an argument in the call.

Syntax:
// definition
function name(x: x_type) {
  // use x here
}

// call
name(value_to_replace_x)

note Note that a parameter isn’t declared with the var or let keywords.

We’ll use our simple logger function again.

Example:
function logger(msg: string) {
  console.log(msg)
}

// when calling the function
// we must include an argument
// for the message parameter
logger("Hello")

This time, we’ve added the parameter msg of type string in the function’s parameter list. Then, we referred to msg where we wanted the value of msg to go in the body.

In the function call, we specify the word ‘Hello’ as the argument. Every instance of the msg parameter in the body will be replaced by whatever we type here.

We can now call the function as many times as we want with different messages.

As an example, let’s call the function a few more times with different messages as the argument.

Example:
function logger(msg: string) {
  console.log(msg)
}

logger("Hello world")
logger("Lovely weather we are having")
logger("I hope it stays this mild")

When we run the example above, all three messages are printed to the screen.

To add multiple parameters to the function, we separate them with a comma.

Example:
function logger(firstName: string, lastName: string) {
  console.log(lastName, ",", firstName, lastName)
}

logger("James", "Bond")

Default parameter values

TypeScript allows us to assign initial values to our parameters. If we don’t specify a value as the argument, the compiler will use the default value instead.

We do this with initialization syntax in the parameter list.

Syntax:
function name(param: param_type = default_value) {
  // body
}
Example:
function greeter(msg: string = "Greetings") {
  console.log(msg)
}

// if no argument is specified
// the default value is used
greeter()

// if an argument is specified
// the argument is used instead
greeter("Good morning")

In the example above, our first function call has no argument specified, so it used the default value in the parameter list.

The second function call did specify an argument, so the default value was not used.

Parameters with default values should be used after any other parameters.

Example:
function greeter(msg: string = "Greetings", name: string) {
  console.log(msg, name)
}

// we cannot specify the second
// argument as the only one, it
// will raise an error
greeter("John")

// we have to specify both
greeter("Good morning", "John")

In the example above, we add a non-default parameter after the default one. When we call the function and specify an argument only for the regular parameter, the compiler will raise an error.

We would have to specify both in this case. The solution to this problem is to place all our default parameters after any regular parameters.

Example:
function greeter(name: string, msg: string = "Greetings") {
  console.log(msg, name)
}

// now it works
greeter("John")

// in both cases
greeter("John", "Good morning")

Rest parameters

Rest parameters allow us to work with multiple parameters as a group.

Typically, we can only specify a single argument for a function. If we try to add multiple arguments, the compiler would raise an error.

Example:
function multiNames(firstName: string) {
  return firstName
}

var result = multiNames("John", "Jane", "Jack", "Jill")
console.log(result)

The compiler raises the error ‘expected 1 arguments but got 4’.

We could take an array as an argument, but the error would be the same.

Example:
function multiNames(firstName: string[]) {
  return firstName
}

var result = multiNames("John", "Jane", "Jack", "Jill")
console.log(result)

We receive the same error, because we’re trying to specify 4 different arguments where a single array should be.

The solution is to use a Rest parameter. A Rest parameter will allow us to specify individual arguments, and have them assigned to an array.

To do this, we prefix the parameter with ... (elipses) and add a pair of square brackets to the parameter type (turning it into an array).

Example:
function multiNames(...firstName: string[]) {
  return firstName
}

var result = multiNames("John", "Jane", "Jack", "Jill")
console.log(result)

This time, the compiler doesn’t raise an error, and when we compile and run the script, we can see the arguments we passed to the function was inserted into the array.

Output:
 [ 'John', 'Jane', 'Jack', 'Jill' ]

note It’s okay if you don’t quite understand the part about arrays, it will make sense once we discuss them in the tutorial lesson on arrays .

How to return a value from a function

Functions can return a value to the caller when we invoke them.

As an example, let’s consider a simple math function that adds two numbers together. We may not want to print that value to the page directly from inside the function, but use it for other calculations somewhere else in our application.

We can return the value from the function and either use it directly, or store it in a data container for later use.

To return a value, we write the return keyword, followed by the value we want to return and a semicolon to terminate the statement.

Syntax:
function name(parameters) {
  // function body
  return value
}
Example:
function add(num1: number, num2: number) {
  return num1 + num2
}

// store the returned value
let result: number = add(5, 3)

// or use it directly
console.log( add(5, 3) )

The example above will add num2 to num1 , and return the result when the function is called.

We call the function twice here to demonstrate that it can be used directly in something like the console.log() statement, or we can assign the returned value to a variable to store it.

Return types

It’s good practice to explicitly specify the type of value a function will return.

We do this by adding a colon and a return type in the function header, after the parameter list, but before the open curly brace.

Syntax:
function name(parameters: parameter_types): return_type {
  // one or more logic statements
  return value
}

When we specify a return type, the function can only return that type.

Example:
// the value that's returned can
// only be of type number now
function add(num1: number, num2: number): number {
  return "num1 + num2"
}

The example above will raise an error because we try to return a string value, when the compiler expects a number value.

When the function doesn’t return a value, we specify the return type as void .

Example:
// non-returning function
function logger(msg: string): void {
  console.log(msg)
}

Arrow functions (function expressions)

A function expression, more commonly known as an arrow function, is a shorthand method of writing a function.

note These are similar to lambdas/anonymous functions in other languages like C#.

Let’s see the syntax first, then break it down.

Syntax:
// definition
let name = (parameters): return_type => {
  // function body
  return value
}

// call
name(parameters)

We don’t use the function keyword or give it a name, we assign the function to a variable instead. The variable will act as the function name and is used to call it.

We also add the => operator (fat arrow) before the function body. The rest of the function is the same as a traditional function.

As an example, let’s consider a simple function that greets a user.

Example:
// traditional function definition
function greeting(name: string): void {
  console.log("Hello,", name)
}

// traditional function call
greeting("John")

The example above will print a hello message to the console when we compile and run it. Now lets convert this into an arrow function.

Example:
// arrow function definition
let greeting = (name: string): void => {
  console.log("Hello,", name)
}

// arrow function call
greeting("John")

We can simplify the arrow function above even more.

When an arrow function only has a single statement in its body, we can remove the curly braces.

Example:
// arrow function definition
let greeting = (name: string): void => console.log("Hello, ", name);

// arrow function call
greeting("John")

If the arrow function returns a value, and the return statement is the only statement in the body, we can omit the return keyword as well.

Example:
// this function
let greeting = (name: string): void => {
  return "Hello," + name
}

// becomes this
let greeting = (name: string): void => "Hello," + name

console.log(greeting("John"))

Let’s see another example of a simple arrow function.

Example:
// log something to the console
let logger = (msg: string): void => console.log(msg)

// add two numbers together
let add = (num1: number, num2: number) => num1 + num2

logger(add(5, 8))
logger(add(-2, 44))
logger(add(815, -20589))

Mini challenge

Now that we know more about functions, try to convert the following logic (from the start of the tutorial) into both a traditional and an arrow function.

Logic:
// number to check
let num : number = 5

// if the number can be divided by two
// without a remainder, it's an even num
if (num % 2 == 0) {
  console.log(num, " is an even number")
} else {
  console.log(num, " is an odd number")
}

If you get stuck, see our solution below.

Solution:
// traditional function
function isEven(num: number): void {

  if (num % 2 == 0) {
    console.log(num, "is an even number")
  } else {
    console.log(num, "is an odd number")
  }
}

isEven(5)
isEven(8)

// arrow function
let isOdd = (num: number): void => {

  if (num % 2 != 0) {
    console.log(num, "is an odd number");
  } else {
    console.log(num, "is an even number");
  }
}

isOdd(-2)
isOdd(14)
isOdd(7)

Summary: Points to remember

  • Functions group our code into smaller reusable units, and are usually responsible for only a single specific task.
  • It’s not enough for a function to be defined, we must call (invoke) it in order to use it.
  • Functions accept one or more parameters that allow different inputs to be used on each call of the function.
  • Default parameters allow us to add a fallback value if an argument is not given.
    • If the header contains both regular and default parameters, the default parameters should be specified last.
  • Rest parameters allow us to group multiple arguments into a single array parameter.
  • Functions can return a single value with the return keyword.
  • Arrow functions are a shorthand syntax of writing a function and simplifies the process.
    • If an arrow function only contains a single statement in its body, the curly braces may be omitted.
    • If an arrow function returns a value, and the return statement is the only one in its body, both the return keyword and the curly braces may be omitted.