We've seen a lot of usage for data parameters in functions, such as number or string values. This is useful when we need to give the function more *information*. When we want to give a function more pieces of *logic*, that's where higher order functions come into play. Just like we can pass in arrays, objects, or primitive values when we call a function, we can also do this with other functions! This means we can have parameters that are functions, and then we can call functions with other functions as arguments!

Using functions as parameters is an example of using **higher-order functions**.

Higher order functions often go hand in hand with functional interfaces, which are a nice way to specify types for functions which we can then use as parameters. Here's an example:

```
interface Change {
(num: number): number;
}
let double: Change = (n: number): number => {
return n * 2;
};
let sub1: Change = (n: number): number => {
return n - 1;
};
let math = (n: number, f: Change): number => {
return f(n);
};
let num0: number = math(4, double);
let num1: number = math(3, sub1);
// num0 is 8
// num1 is 2
```

In this example, we're passing around functions as arguments when we call the **math** function. Then, within the **math** function, we call the other function we passed in as an argument! By using functions in this way, we're seeing how higher-order functions can be useful when we want to apply different logic.

We will work towards generic filter, map, and reduce functions which will follow this idea higher-order functions.