Invest with Cake DeFi and get guaranteed returns from your crypto assets. Register Now
All Articles

TypeScript - Declare a function callback type

TL;DR To define the function callback type. You could declare an interface that has a call signature. Or define a new type.

interface Greeter {
  (message: string): void;
}

//OR
//type Greeter = (message: string) => void;

function sayHi(callback: Greeter) {
  callback('Hi!')
}

What is a callback?

A callback is a term that refers to a coding design pattern where you can pass a function to another function. So that within the called function, it can “call back” the function you passed to it.

Do you use a callback in JavaScript before ?!. Often seen in many scenarios. Let take a look at the example below.

function greeter(message) {
  console.log(`${message}, how are you doing?`)
}

function sayHi(callback) {
  callback('Hi!')
}

sayHi(greeter)

So there is a function sayHi, that accept another function as an argument and will execute this function when I start to call sayHi. The problem is I don’t know how the callback looks like, what is the type of its arguments. You can even call the function without any parameter, or multiple parameters. It doesn’t matter at all.

In TypeScript, more often I would define an interface with a call signature like that.

interface Greeter {
  (message: string): void;
}

function sayHi(callback: Greeter) {
  callback('Hi!')
}

By declaring an interface that has a call signature named Greeter which accepts a string as an argument. We can start to see callback detail.

TypeScript - Declare a function callback type

If we change the signature of function greeter to number instead of string, it will show you an error that the type doesn’t match. Now you have a strong type callback instead of just passing around function as we usually do in JavaScript.

TypeScript - Declare a function callback type

Generalize the callback type

We could also use generic to generalize the use case of callback with one parameter as below. By doing so, you don’t have to define a new interface with a new name each time you need to use a callback with one parameter. Usually, the callback will not return any value, I default the T2 type to void. But if you need to return a value from a callback function, you can specify the type for T2.

interface CallbackOneParam<T1, T2 = void> {
  (param1: T1): T2;
}

See the two below examples in action.

Void

function greeter(message: string) {
  console.log(`${message}, how are you doing?`)
}

function sayHi(callback: CallbackOneParam<string>) {
  callback('Hi!')
}

sayHi(greeter)

With type

function greeter(message: string) {
  return `${message}, how are you doing?`
}

function sayHi(greeter: CallbackOneParam<string, string>) {
  let message = greeter('Hi!')
  console.log(message)
}

sayHi(greeter)

Alternative

There are other ways to do it, you can refer to this question. One that worth mentioned is to define a type, but doing so will enforce the parameter name of this type and the function that you declare to be the same.

type MyHandler = (message: string) => void

Reference

Published 11 May 2019

Recent Posts

Casting a JSON object to a TypeScript class

Not all the time we need to cast from JSON object to a class, but sometimes it is really helpful. Use class-transformer to transform JSON object to class instance

Angular [(ngModel)] and debounce

In the use case of search, we don't want to hit the server endpoint every time user presses a key, it should flood them with a storm of HTTP requests. Basically, we only want to hit it once the user has stopped typing after sometimes (for instance 300ms) instead of with every keystroke.


Follow @tuantrungvo on Twitter for more!