Cover photo credit: Ceos3c
Introduction
You are reading this article because of a function (a method to be more precise). Functions make up an "underrated" most of our functional technology, and this is no different from Typescript(TS). You might understand the logic and syntax behind functions in Javascript(JS), and if you are curious to know how it works in TS, I've got you covered in this week's article.
Function Inference
Function with single parameters
Check out the function below:
function addTwo(num) {
return num + 2;
}
addTwo(46);
The code above looks all good, and it is. However, if we just hover around it to check its data type, it is inferred to as Any
(Discussed in the previous article of this series). We know that's bad for our team because Any
escape's type and static checking and attract messy bugs.
We can fix this by simply mandating the parameter to be a number. Here:
// Specify data type
function addTwo(num: number){
return num + 2
}
addTwo("46"); // Notice this error
- In the code above, I threw in an error that would trigger static checking. The point you should note is that if I did not specify the data type of the number, then TS would not have noticed that error. Functions in TS have this behavior and it is up to you to specify that you don't want the inferred
Any
data type.
Function with multiple parameters
Let's have a function with multiple parameters:
function signUpUsers(name, age, isRegistered) {
console.log(name, age, isRegistered);
}
signUpUsers(22, "thirty-three", 3);
In the code above, static checking on all parameters returns each parameter as an Any
data type. The signUpUsers
function receives inputs that are not correct in this context, and TS can't warn us with static checking. We can simply add a data type to each parameter to avoid this.
function signUpUsers(name: string, age: number, isRegistered: boolean) {
console.log(name, age, isRegistered);
}
signUpUsers(22, "thirty-three", 2); // error activates static checking
- Static checking is now activated above, and we start getting those error warnings
Arrow functions
Sometimes it might be necessary to use arrow functions and use default parameters, while prompting a user for input for other parameters, something like this:
let okayLogin = (name: string, email: string, isRegistered: Boolean) => {
// Some code
};
okayLogin("kelvin", "kelvin@kelvin.com");
- In the last line above, the
isRegistered
parameter is not satisfied and TS static checking throws up an error.
Assuming we wanted to set isRegistered
to a default boolean, and also wanted TS to ignore static checking for that, we could set a default value for it.
let okayLogin = (name: string, email: string, isRegistered: Boolean = true) => {
// Some code
};
okayLogin("kelvin", "kelvin@kelvin.com");
- The boolean is auto set to true except a different value is given.
Return statements
Single return statements
For most of the function examples, we have only looked at making the input match the data type of the parameters. But can the return statements also display type errors? Let's find out. In the snippet below:
function addNumbers(num: number) {
return "hello";
}
- Since the parameter is a number, I am also assuming that the output should be a number, but TS doesn't give any static check warnings.
If this was a team with hundreds of thousands of lines of code, this would be an issue. To solve this, we have to specify the output:
function addNumbers(num: number): number {
// specify output
return "hello"; // error
}
- After specifying what should be returned, TS static checking comes into play.
Multiple return statements
What if we had a function that could return different data types based on conditions?
function updateStatus(val: number) {
if (val > 5) {
return true;
} else {
return "status 404 not found";
}
}
- The output of the function above is open to
any
data type which defeats the purpose of Typescript.
Specifying a return
statement for one data type will enforce static checking errors, so we have to specify multiple return
statements. Like below:
function updateStatus(val: number): boolean | string {
if (val > 5) {
return true;
} else {
return "status 404 not found";
}
}
It is also simple to transform the code above to an arrow function:
let updateStatus = (val: number): boolean | string => {
if (val > 5) {
return true;
} else {
return "status 404 not found";
}
};
Void and Never functions
Sometimes we might want a function that to return nothing, to do this, we specify the function to return a void
type or a never
type.
with void
function handleError(error: string): void {
throw new Error(error);
}
- The
void
type does static checking, if any attempt to mutate the function to add areturn
statement to it.
with never
Meanwhile, never
more suited to throwing errors:
function handleError(error: string): never {
throw new Error(error);
}
Difference between void and never
In TypeScript, void and never are both used to represent the absence of a value, but they have different meanings.
void
is a type that represents the absence of a value. It is typically used as the return type of functions that do not return a value, or when a variable is not assigned any value. For example, the following function returns void:
function logMessage(message: string): void {
console.log(message);
}
- In this case, the function
logMessage
does not return a value, so its return type isvoid
.
On the other hand, never
is a type that represents a value that never occurs. It is typically used to indicate that a function is meant to never return a value or that a variable cannot have a value. For example, the following function returns never:
function throwError(error: string): never {
throw new Error(error);
}
- In this case, the function
throwError
throws an error and never returns a value, so its return type isnever
.
It is the intent that matters, void
should be used to indicate that a function does not return a value, while never
indicates that a function should never have a value.
Conclusion
Functions have proven themselves to be the unsung heroes of our coding escapades, and in Typescript, they take on a whole new level of charm. By harnessing the power of static type checking, we can sprinkle our functions with enchanting data types and wave goodbye to pesky bugs.
From inferring the right types for single and multiple parameters to crafting arrow functions with default values that tickle our coding taste buds, Typescript has us covered. It's like a magical spell that keeps our code in check, ensuring we play by the rules and catch errors before they have a chance to misbehave.
But it doesn't stop there! Our trusty functions can even entertain us with their return statements. We've learned how to coax them into revealing their true type identities, whether it's a single type or a delightful union of possibilities. We've witnessed the power of void, where functions gracefully bow out without returning a value, and never, the enigmatic type that assures us a value will never, ever emerge.
So, as we bid farewell to this journey through Typescript functions, let's remember to embrace their quirks and unleash their full potential. With static checking as our guide, we can create code that dances with joy, bringing laughter and stability to our programming endeavors. So go forth, fellow developers, and let your functions shine with all their magical might!