What if we could use functions as a special type? Let me make my point clearer.Consider the following two functions:
function add(n1: number, n2: number): number {
return n1 + n2;
}
function printResult(num: number): void {
console.log('Result: ' + num);
Now suppose we have a variable as follows:
let combineValues;
In such a case, the type of combineValues
variable is of any
type, but as I said, any
is not very useful, so I want to do something like this:
combineValues = add;
That is, put the add
function in combineValues
. As you know, in JavaScript, we can do something like this and even execute this variable as a function:
let combineValues;
combineValues = add;
console.log(combineValues(8, 8));
If we compile this code with the command tsc app.ts
and open the code in the browser, we will get the number 16
. The problem is that currently the combineValues
variable is of type any
so it accepts any value, even if we give it a number:
let combineValues;
combineValues = add;
combineValues = 5;
console.log(combineValues(8, 8));
The code above compiles without error, but we encounter an error in the browser because we made a logical mistake. By assigning the number 5
to combineValues
, we have turned it into a normal variable that has the number 5
in it, and obviously such a variable cannot be implemented and we receive an error. To solve this problem, you can set the variable type to function
:
let combineValues: Function;
combineValues = add;
combineValues = 5;
console.log(combineValues(8, 8));
By doing this in TypeScript, we immediately get an error that tells us that the number 5
is not a function
. So this solves our problem, but it is still not a perfect method because Function
means any function! In other words, by doing this, the following code will be allowed:
let combineValues: Function;
combineValues = add;
combineValues = printResult;
console.log(combineValues(8, 8));
Now, if we compile the code and open the browser, the result will be as follows:
Result: 8
undefined
Because printResult
takes only one parameter, but we have set it to combineValues
and then given two parameters to combineValues
! The typescript can't get any error from our code because we only set the Function
type for it and printResult
is also a function.
Our solution is function types:
let combineValues: () => number;
As you can see, this syntax is very similar to arrow functions, but it has nothing to do with them. By putting the parenthesis sign and then the arrow sign, we say that the combineValues
type is supposed to be a function (of course, a function that does not accept any parameters) and then we specify its output or return by adding number
, which here is number
.
Our function takes parameters, so we need to add these parameters to it:
let combineValues: (a: number, b: number) => number;
combineValues = add;
combineValues = printResult;
Now I have determined that combineValues
takes a function that has two parameters and both are number
s and finally returns a number
. It is also not necessary that the names of these parameters are exactly the same as the main function, but anything (such as a
and b
) can be placed instead. By doing this, the second line (assignment add
) will be fine, but for the third line (assignment printResult
) we will encounter an error because our definition does not match printResult
(two arguments in our definition instead of one argument in printResult
and also return type of void
type in printResult
against number in our definition).
We can implement the same logic for callback functions. For example, consider the following function:
function addAndHandle(n1: number, n2: number, cb) {
const result = n1 + n2;
cb(result);
}
The third parameter of this function is cb
or callback and it is supposed to be a function that is executed inside our function and receives the result
value. Now, with the same logic as before, we can specify the type of callback explicitly:
function addAndHandle(n1: number, n2: number, cb: (num: number) => void) {
const result = n1 + n2;
cb(result);
}
That is, cb
requires a number as its argument and returns void
. why void
? Because I want cb
to execute the console.log
statement, so it will not have any return
statement. If you want cb
to do more things and return
something, you can change the above code. Now we can simply call it:
addAndHandle(10, 20, (result) => {
console.log(result);
});
As you can see, I've given it an arrow function for the third parameter (note that this is really a function and not a type - it doesn't have a colon) which console.logs
the value of the first two parameters. Now, if we go to the browser after compiling the code, we will see the output 30
, which is the correct value.
Of course, the interesting point here is that if we write cb
with the return
statement, no error will be given to us:
addAndHandle(10, 20, (result) => {
console.log(result);
return result;
});
We specified above that cb
should output void
, so why doesn't it give us an error for return? Because we specified void
in the addAndHandle
function, which means that we have nothing to do with the cb
output in the addAndHandle
function, so void
here means the output of the cb
function in the addAndHandle
function is not important to us. In simpler language, in such a case, void
does not say that the cb
function does not return
anything, but it says that if a value is returned, it does not matter to us (in addAndHandle
, of course).