How to Use Typescript to Point to a Function
Jun 17, 2020 • 6 Minute Read
Introduction
Writing functions in TypeScript is a fundamental task when describing how to do something. Depending on the context, the functions sometimes need to be referenced or pointed to. In this guide, you will learn two approaches of pointing to a function:
- First, by declaring a variable with a type.
- Second, by introducing an interface that describe the type of function for a variable. This is useful in cases where you need to declare new variable with the same signature as the function and use it in a specific context or domain.
We will work with a code example of a financial transaction.
Approach 1: Without an Interface
Let's say that printTransactionDetails() is a function that takes three parameters: transactionType of type string, amount of type number, and category of type string. Based on the value of transactionType, it decides whether a transaction is a credit or a debit and assigns it a value of either Spent or Earned. Finally, it generates a string and prints on the console before it is returned.
function printTransactionDetails(transactionType: string, amount: number, category: string): string {
let creditOrDebit: string = (transactionType === "debit") ? 'Spent' : 'Earned';
let result: string = creditOrDebit + " $" + amount + " in " + category;
console.log(result);
return result;
}
Now, let's say you need a variable, printFoodTransaction, that prints the details of a food transaction. It has a function type and its signature matches the printTransactionDetails() function.
You declare it as below.
let printFoodTransaction: (transactionType: string, amount: number, category: string) => string;
How would you point printFoodTransaction to the printTransactionDetails() function?
You can do so by assigning printTransactionDetails to printFoodTransaction.
printFoodTransaction = printTransactionDetails;
To print a food transaction, call the printFoodTransaction function and pass the values for transactionType, amount, and category.
printFoodTransaction("debit", 100, "Food")
Make sure your code looks like this.
function printTransactionDetails(transactionType: string, amount: number, category: string): string {
let creditOrDebit: string = (transactionType === "debit") ? 'Spent' : 'Earned';
let result: string = creditOrDebit + " $" + amount + " in " + category;
console.log(result);
return result;
}
let printFoodTransaction: (transactionType: string, amount: number, category: string) => string;
printFoodTransaction = printTransactionDetails;
printFoodTransaction("debit", 100, "Food")
When you run the code in your editor or on the command line, you should see the output below.
Spent $100 in Food
If you need another variable, say, printUtilityTransaction, to print transaction details for a utility category, you will need to declare its type again, point it to the printTransactionDetails function by assigning the value, and call the printUtilityTransaction function with three arguments.
let printUtilityTransaction: (transactionType: string, amount: number, category: string) => string;
printUtilityTransaction = printTransactionDetails;
printUtilityTransaction("credit", 80, "Utilities");
This time, when you run the code, you should see the output below.
Spent $100 in Food
Earned $80 in Utilities
This is one approach of pointing a variable to a function in TypeScript. It is not incorrect, but you can see that there is code duplication when you are describing the type of each variable (printFoodTransaction, printUtilityTransaction).
The second approach will tackle this problem and make your code reusable.
Approach 2: With an Interface
Instead of defining the types repeatedly, you can make use of TypeScript interfaces. Here, transactionPrinter is an interface that describes the function type. This is like declaring a function with a list of parameters and a return type.
Each parameter requires a name and its corresponding type, which helps to define a contract with the code.
interface transactionPrinter {
(transactionType: string, amount: number, category: string): void;
}
With the interface defined, the two variables, printFoodTransaction and printUtilityTransaction, can now use this function type. Both printFoodTransaction and printUtilityTransaction are of type transactionPrinter. You can assign them a function value printTransactionDetails (of same type) right at the time of declaration. It makes your code concise, reusable, and easy to read.
let printFoodTransaction: transactionPrinter = printTransactionDetails;
printFoodTransaction("debit", 100, "Food");
let printUtilityTransaction: transactionPrinter = printTransactionDetails;
printUtilityTransaction("credit", 80, "Utilities")
Make sure your code after this refactor looks like this:
function printTransactionDetails(transactionType: string, amount: number, category: string): string {
let creditOrDebit: string = (transactionType === "debit") ? 'Spent' : 'Earned';
let result: string = creditOrDebit + " $" + amount + " in " + category;
console.log(result);
return result;
}
interface transactionPrinter {
(transactionType: string, amount: number, category: string): void;
}
let printFoodTransaction: transactionPrinter = printTransactionDetails;
printFoodTransaction("debit", 100, "Food")
let printUtilityTransaction: transactionPrinter = printTransactionDetails;
printUtilityTransaction("credit", 80, "Utilities");
You should see the output below when you run this code.
Spent $100 in Food
Earned $80 in Utilities
Conclusion
In this guide, you learned two approaches for pointing to a function in TypeScript. When working with a small codebase or program, you may choose any one of these approaches. In complex applications, using interfaces to describe the function types enables you to write the code using the DRY (don't repeat yourself) principle. It lets you define contract in the code and perform type checking, especially with JavaScript, which does not support strong typing out of the box.