Another way we can type check is by defining the type first before referencing that type with our function.
If you have been keeping up with this series, in part 2, we explored how interfaces could be given call signatures to define the types of the parameters and return value as well.
Functions can also be type checked by using generics which allows us to relate the input type to the output type. Generics will be covered in a later article, for now, just note that we can use generics by calling a type parameter in our function signature.
From the code snippet, we have 2 generic types:
O. These types represent the types for
arr2 respectively. With generics, we have linked the types for our inputs with our output. Therefore, we can expect the output to have a type of
O given the union assignment within the array which will be defined by the arguments passed onto the functions. More on union types will be covered in a later article.
When assigning a function to a variable, the TypeScript compiler is able to infer the type if defined on only one side of the assignment.
With contextual typing, the amount of code you need to write will be cut down.
Optional and Default Parameters
We can see that with required parameters, we are constrained to having the exact number of parameters and that each of these parameters must exist.
In order to reduce the strictness of TypeScript on parameters, we can use optional and default parameters. To make a parameter optional, we add a
? at the end of it. We can also assign a default value to a parameter in the case where the argument is not provided or is
If we want to work with multiple parameters as a group or an unknown number of parameters, we would have to use
… followed by the parameter name. This is known as a rest parameter. For rest parameters, the compiler will treat them as an array and evaluate the types within that array for type correctness.
Another neat feature in TypeScript is that it is able to catch errors when it comes to
this can be tricky to deal with at times as it’s reference changes based on context.
From the code snippet above,
use strict was defined for consistency. This results in
passedIdentity() to be
undefined instead of
window for the browser or
global for node.
passedIdentity() was defined within the same class, the context of
passedIdentity() was shifted globally when it was assigned to the variable
passedArrowIdentity() retained its
WhoThis by using the arrow function which binds
this to the object.
"this" Parameters in Callbacks
this within callback functions, you can annotate them within your functions.
TypeScript will check the instance of
this and ensure that the types are correct. In the case of
this was typed as
WhoThis. However, TypeScript recognized that
this has a type of
void instead and threw an error. For
passedArrowIdentity(), since it was an arrow function, it cannot have a
this parameter as the type is already implied to be
Since a function can accept different types of arguments and output different return types as well, we can use overloads to encompass those behaviors.
TypeScript will go through each of the overloads and checks to see if the arguments used for the function calls match the overload signatures. Note that
guessTypes(guess: any): any is not part of the overloads, therefore there are only three overloads.
In this article, we learn that we can be strict with the number and types of functions parameters and the type of it’s return value.
We can also “widen” the type strictness with optional and default parameters, allowing for different behaviors when calling our functions.
this is important in type checking our functions, especially for those that get passed around from one context to another.
And finally, with overloads, our functions are able to accept different combinations of input and output types.