Introduction to TypeScript Functions: Anonymous Functions and More

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Functions are small blocks of code that take in some inputs and may return some output or have side effects. A side effect means that it modifies some variables outside the function.

We need functions to organize code into small blocks that are reusable.

Without functions, if we want to re-run a piece of code, we have to copy it in different places. Functions are critical to any TypeScript program.

In this article, we continue to look at different parts of TypeScript functions, including passing in a variable amount of arguments, recursion, function nesting, and defining functions in objects.

Calling Functions with More Arguments that Parameters

In TypeScript, we can call a function with more arguments than parameters. If we just pass them in without accessing them from the argument object, they’ll be ignored. You can get the extra arguments that aren’t in the parameters with the argument object and use them. The argument object has the parameters with numerical keys just like the indexes of an array. Another way to access extra arguments is through the rest parameter.

For example, if we call the add function with extra parameters:

function add(a: number, b: number, ...rest: any){  
  console.log(arguments);  
  return a + b;  
}  
add(1, 2, 3);
Enter fullscreen mode Exit fullscreen mode

The ...rest part of the signature captures the parameters that we don’t expect to be passed in. We used the rest operator, which is indicated by the 3 periods before the word rest to indicate that there might be more parameters at the end after b. We need this in TypeScript so that we don’t get the mismatch between the number of parameters and the number of arguments passed in. In vanilla JavaScript, ...rest is optional.

In the console.log call, we should get:

0: 1  
1: 2  
2: 3
Enter fullscreen mode Exit fullscreen mode

Variable Scope in Functions

Functions inside shouldn’t be accessible outside of functions unless they are global variables. We should avoid defining global variables as much as we can to prevent bugs and hard to trace errors since they can be accessed anywhere in the program. To prevent defining global variables, we should use let to define variables and const to define constants. For example, we should define functions like so:

function add(a: number, b: number){  
  let sum = a + b;  
  return sum;  
}
Enter fullscreen mode Exit fullscreen mode

In this case, we have sum which is only accessible within the function since it’s defined with the let keyword.

Anonymous Functions

Anonymous are functions with no names. Since they have no name, they cannot be referenced anywhere. They are often passed into other functions as callback functions, which is called when the function is passed into an argument. However, you can assign anonymous functions into a variable so it becomes a named function.

They can also be self executing. This is means that you can define the function and make it run immediately. For example, if we write:

const sum = (function(a: number, b: number){  
  return a + b;  
})(1, 2);
console.log(sum) // log 3
Enter fullscreen mode Exit fullscreen mode

We log 3 because we defined a function to add 2 numbers, and then passed in 1 and 2 as the arguments immediately after by wrapping the function in parenthesis and then passed the arguments to it.

Recursion

You can call the same function from within itself in TypeScript. This is called recursion. All recursive functions must have an end condition, which is called the base case, so that it knows when it stops executing. Otherwise, you can get a function that’s called an infinite number of times, which will crash the browser.

To write a recursive function, we can write:

function sumOfSquares(num: number): number {  
  let sum: number = Math.pow(num, 2);  
  if (num == 1) {  
    return 1  
  } else {  
    return sum + sumOfSquares(num - 1)  
  }    
}
Enter fullscreen mode Exit fullscreen mode

In this example, we wrote a function to compute the sum of squares for a given number. We compute the square of num and then if we have num equal to 1 then we return 1. Otherwise, we return the sum of sum plus the result of call sumOfSquares on num — 1 . We keep reducing num so that we can reach our base case of 1, adding up the results while doing so.

Nesting Functions

Functions can be nested within each other. This means that we can define a function inside another function. For example, we can write:

function convertToChicken(name: string){  
  function getChickenName(name: string){  
    return `Chicken ${name}`;  
  }  
  return getChickenName(name)  
}
Enter fullscreen mode Exit fullscreen mode

In this case, we called getChickeName inside the convertToChicken call. So if we write convertToChicken('chicken') , then we get 'Chicken chicken' since we called get getChickeName and returned the result. The scope of variables is the name. let and const are block-scoped so they cannot be accessed outside of the original function that’s defined, but they are available in the nested function, so if we have:

function convertToChicken(name: string) {  
  let originalName = name;  function getChickenName(newName: string) {  
    console.log(originalName)  
    return `Chicken ${newName}`;  
  }  
  return getChickenName(name)  
}
Enter fullscreen mode Exit fullscreen mode

Then originalName will still be defined in the console.log.

Defining Function in an Object

We can define a function in an object in a few ways. We can use the function keyword or arrow function as usual, but we can also write it with a shorthand for the function keyword. For example, if we have a bird object and we want to define the chirp function, we can write:

const bird = {  
 chirp: function(){  
   console.log('chirp', this)  
  }  
}
Enter fullscreen mode Exit fullscreen mode

or use the following shorthand:

const bird = {  
 chirp(){  
   console.log('chirp', this)  
  }  
}
Enter fullscreen mode Exit fullscreen mode

The 2 are the same since the chirp function will have the bird object as the value of this.

On the other hand, if you use an arrow function:

const bird = {  
 chirp: () => {  
   console.log('chirp', this)  
  }  
}
Enter fullscreen mode Exit fullscreen mode

We’ll get an error from the Typescript compiler because the value of this is the globalThis value, which the TypeScript compiler doesn’t allow. We get the error “The containing arrow function captures the global value of ‘this’.(7041)” when we try to compile the code above.

TypeScript functions allow us to organize code into small parts that can be reused. There’re many ways to define a function, but sticking to the commonly recommended ways like using arrow functions and not using arguments too much is recommended.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .