4

Understanding TypeScript Function Types: A Beginner's Guide

 1 year ago
source link: https://dmitripavlutin.com/typescript-function-type/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Functions are the small pieces of logic that together form applications. If you write applications in TypeScript, knowing function types is a must.

This guide covers everything you need to know to start using TypeScript function types.

1. TypeScript function type

Functions in JavaScript/TypeScript are first-class objects. You can assign functions to variables, use functions as arguments to other functions, and even return functions.

Knowing how to type functions in TypeScript is a must if you want to pass around functions as objects.

Let's start with a simple case: a function that sums 2 numbers and returns the sum.

Here's the function in plain JavaScript:



// JavaScript
function sum(a, b) {
return a + b

sum() is a function returning the sum of its 2 arguments.

In plain JavaScript, you know that a and b arguments have to be numbers, and the returned value also has to be a number.



// JavaScript
function sum(a, b) {
return a + b
console.log(sum(4, 3)); // logs 7

In the above examples the arguments 4 and 3, as well the returned value 7 are all numbers.

Having the information about parameter and return types, you can easily translate that into a TypeScript function type of the sum():



// TypeScript function type
(a: number, b: number) => number

(a: number, b: number) is the part that indicates the parameters and their types. Enumerate as many parameters as you want. After the fat arrow indicate the return type: => number. That's it.

(Note: the function type looks similar to an arrow function. But they are different things.)

Working with function types, because of their length, is more convenient by storing them into a type alias. A type alias type reuse in multiple places:



// Sum is a type alias
type Sum = (a: number, b: number) => number

Having the Sum type, you can use it to annotate any place you want where the function object is passed around in TypeScript.

First, of course, you can assign the function to a variable:



type Sum = (a: number, b: number) => number
// Assign to variable
const sum1: Sum = function(a: number, b: number): number { return a + b } // OK
const sum2: Sum = function(a, b) { return a + b } // OK

Open the demo.

In the example above sum1, as well as sum2 is of type Sum.

sum2 function doesn't have the parameter and return types indicated: all because TypeScript infers these types from the Sum. In the examples that follow I'm going to use type inference on functions to avoid repetition.

In case of an higher-order function, you use the function object as an argument or even return it from another function:



type Sum = (a: number, b: number) => number
// Sum as argument
func(1, 2)
someFunc1((a, b) => a + b) // OK
// Sum returned
return (a, b) => a + b
someFunc2()(1, 2) // OK

Open the demo.

2. TypeScript function type guide

To help you understand better how to use the function types, let's see a couple of guiding ideas.

1) Use ? to indicate an optional parameter:



type SumOpt = (a: number, b?: number) => number
const sumOpt: SumOpt = function sum(a, b) {
if (b === undefined) {
return a
return a + b
sumOpt(2) // OK

Open the demo.

?b in the SumOpt type is an optional parameter. The second argument can be omitted when invoking sum(2).

2) A rest parameter is typed using the three dots and an array type (...rest: T[]):



type SumRest = (...numbers: number[]) => number
const sumRest: SumRest = function sum(...numbers) {
return numbers.reduce((sum, number) => sum + number)
sumRest(1, 2) // OK

Open the demo.

...numbers: number[] inside of the function type indicates a rest parameter.

3) The regular and the arrow functions have the same type:



type Sum = (a: number, b: number) => number
const regularFunc: Sum = function(a, b) { return a + b } // OK
const arrowFunc: Sum = (a, b) => a + b // OK

Open the demo.

regularFunc is a regular function and arrowFunc is an arrow function. Both are Sum types.

4) The parameter names in the function and the function type can be different:



type Sum = (a: number, b: number) => number
const sumDiffParam: Sum = function(n1, n2) { return n1 + n2 } // OK

Open the demo.

It's acceptable that the function type has the parameter names a and b but the function parameters n1 and n2.

5) The function can have fewer parameters than the function type:



type Sum = (a: number, b: number) => number
const sumShort: Sum = function (a) { return a } // OK
const sumShorter: Sum = function () { return 0 } // OK

Open the demo.

sumShort and sumShorter have fewer parameters than the Sum type, still, they are Sum type.

But the function cannot have more parameters than the function type:



type Sum = (a: number, b: number) => number
const sumLonger: Sum = function (a, b, c) { return a + b + c } // Type error!

Open the demo.

6) The return type of an async function must be a promise Promise<T>:



type SumAsync = (a: number, b: number) => Promise<number>
const sumAsync: SumAsync = async function (a, b) {
return await a + b
} // OK

Open the demo.

sumAsync is an async function. The return type of an async function must always be a promisePromise<T> type (which is a generic type).

3. TypeScript method type

A method is a function that exists and is executed in the context of an object. Method types in TypeScript have to exist inside of the object type.

You can define methods on interfaces:



interface ObjectWithMethod {
sum(a: number, b: number): number

or even use a type alias:



type ObjectWithMethod = {
sum(a: number, b: number): number

ObjectWithMethod is an object type having a method sum(). The first and second parameter types (a: number, b: number) are numbers, and the return type is also a number : number.

Remember an important difference. The function type uses the fat arrow => to separate the parameter list from the return type, while the method type uses the colon :.

Let's look at an example:



interface ObjectWithMethod {
sum(a: number, b: number): number
const object: ObjectWithMethod = { // OK
sum(a, b) { return a + b }

Open the demo.

object is of type ObjectWithMethod and contains a method sum().

Of course, you can add as many method types as you need to an object type:



interface ObjectWithMethod {
sum(a: number, b: number): number
product(a: number, b: number): number
abs(a: number): number
// etc...

4. TypeScript function interface

Another interesting way to write the function type is using a TypeScript function interface (also named function call signature).

TypeScript function interface looks similar to an object type interface. The function interface doesn't have the method name written:



interface SumInterface {
(a: number, b: number): number

SumInterface is a function interface. Note that in the expression (a: number, b: number): number there is no function name indicated.

The sum() function used until is also SumInterface type:



interface SumInterface {
(a: number, b: number): number
const sum: SumInterface = function(a, b) { return a + b } // OK

Open the demo.

Most of the time you will use the regular TypeScript function type (a: number, b: number) => number instead of a function interface.

But you can benefit from the function interface when you want to add properties to the function object. Let's add the property description to the sum function type:



interface SumWithDescription {
(a: number, b: number): number
description: string
const sum: SumWithDescription = function(a, b) {
return a + b
sum.description = 'A function that sums two numbers'

Open the demo.

SumWithDescription on top of being a function, also has a description property of type string.

5. Conclusion

Writing a TypeScript function type is pretty simple:



type Sum = (a: number, b: number) => number

Indicate the parameter types in a pair of parentheses, put the fat arrow =>, and the return type.

In the case of methods, you have to define the method on the type of the object:



interface ObjectWithMethod {
sum(a: number, b: number): number

Again, put the parameters into a pair of parentheses, then put a colon : and finally indicate the method return type.

Now you should be ready to type functions in your TypeScript code.

How can you type a function that can be invoked in multiple ways? Follow the post TypeScript Function Overloading to find more information.

Have any questions about function types? Write a comment and let's discuss!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK