NOTE: This is cross-post from my newsletter. I publish each email after it’s sent. Subscribe to get more content like this earlier right in your inbox! 📧.
Hello 👋🏻
Today I want to write a little bit about functions overloads in TypeScript. I will explain what is function overload and how to do it. In the next section, I will cover why you may want to overload your functions and what is a proper way of doing it.
During this article, I assume that you have at least basic knowledge of TypeScript.
Table of contents
What
Function overloads is a way of telling TypeScript that this function may take different arguments.
Let’s jump into an example:
interface Data {
postalCodes: string[];
country: string;
}
const data: Data = {
postalCodes: ['123', '422'],
country: 'PL'
}
This is a bit contrived example but it illustrates the point. I have an object data
which fulfills interface Data
. This object has two keys postalCodes
& country
which are string[]
and string
type respectively.
Below I have getDataByKey
which is a helper to get either postalCodes
or country
.
function getDataByKey(data: Data, key: 'postalCodes' | 'country') {
return data[key];
}
const postalCodesRetrieved: string[] = getDataByKey(data, 'postalCodes')
Everything looks nice so far but at the last line I want my postalCodesRetrieved
to be array of string. Yet compiler will return and error:
Type 'string | string[]' is not assignable to type 'string[]'.
Type 'string' is not assignable to type 'string[]'.
You can find a playground with this problem under this link.
Why & How
How to fix it? You can use function overloading:
function getDataByKey(data: Data, key: 'postalCodes'): string[]
function getDataByKey(data: Data, key: 'country') : string
function getDataByKey(data: Data, key: 'postalCodes' | 'country') {
return data[key];
}
I write two overloads for getDataByKey
: one is taking country
as a key
and returns string
. Another one takes postalCodes
and returns string[]
. Thanks to that I can use getDataByKey
with both keys:
const postalCodesRetrieved: string[] = getDataByKey(data, 'postalCodes')
const countryCodesRetrieved: string = getDataByKey(data, 'country')
You can even see that this function is overloaded by hovering:
Link to TypeScript playground with code from above.
Function overloads in an arrow function
interface GetData {
(data: Data, key: 'postalCodes'): string[];
(data: Data, key: 'country'): string
}
const getData: GetData = (data, key) => {
return data[key];
}
const postalCodesRetrieved: string[] = getData(data, 'postalCodes');
const counryRetrieved: string = getData(data, 'country');
This is working by GetData
interface where overload is happening. Thanks to that I don’t need to type data
& key
arguments anymore. Playground link
Function overloads in class methods
class DataGetter {
getData(data: Data, key: 'country'): string;
getData(data: Data, key: 'postalCodes'): string[];
getData(data: Data, key: 'postalCodes' | 'country') {
return data[key];
};
}
const dataGetter = new DataGetter();
const postalCodesRetrieved: string[] = dataGetter.getData(data, 'postalCodes')
const counryRetrieved: string = dataGetter.getData(data, 'country')
It looks almost the same as for normal function but here getData
method is overloaded. Playground link
Summary & TL;DR
In this post, I presented a way of telling TypeScript that the same function can be called with different parameters or returns different results. This is a function overloading. You can overload class methods too. In the simplest example, you need to write a declaration of override function at the top of a function definition.
Do you use it? If so where? Drop a comment below.
You can find all playgrounds links here:
Top comments (3)
heh, not work without args type bit.ly/arrowOverload
yeah that's true, but you can get it all working by simply casting the return value type to
any
like this
Sad that it doesn't support union types 😥. Is using
@ts-expect-error
as a workaround in your opinion a good solution?