Compare function overloads and generics

Here, I've got a function called returnWhatIPassIn, and it takes an input of unknown and returns an input of unknown so whatever I pass in here it's going to return unknown.


export function returnwWhatIPassIn(input: unknown): unknown {
return input
}

I'm not really fulfilling the promise of this function's name. I can fulfill it by using a function overload for each member of the thing that I want to do.

So I can do export function and have input be a string and suddenly I can pass in strings now. And that will return me a string.


export function returnwWhatIPassIn(input: string): string

I can also add another overload here which will be a number. So if I pass 12 to returnWhatIPassIn then it will return me a number.


export function returnwWhatIPassIn(input: number): number
...
const result = returnWhatIPassIn(12)

The issue here is that I'm going to have to add an overload for everything I can possibly imagine using this function for, which is a little bit tricky. If you have a set number of things that you want to pass in and return then that might be useful, but the real way to do this is with a generic.

So I can add TInput to returnWhatIPassIn. I replace all the unknowns with TInput and just return the input in the function body.


export function returnwWhatIPassIn<TInput>(input: TInput): TInput {
return input
}

Now, whatever I pass in is going to get returned to me. So I can pass in literally anything and it's all going to get returned to me. This is a good way of thinking about the difference between function overloads and generics.

Transcript

0:00 Here, I've got a function called returnWhatIPassIn. It takes an input of unknown and returns an input of unknown. Whatever I pass in here, it's going to return unknown. I'm not really fulfilling the promise of this function's name. I can fulfill it by using a function overload, if I want to, for each member of the thing that I want to do.

0:20 I can do export function and have this be a string. Suddenly, I can pass in strings now, which is good, and that will return me a string. I can also add another overload here, which will be a number, for instance. If I add in 12 here, then it will return me a number. Great.

0:37 The issue here is that I'm going to have to add an overload for everything I can possibly imagine using this function for, which is a little bit tricky. If you have a set number of things that you want to pass in and return, then that might be useful. The real way to do this is with a generic. I can add just T in here, or let's say TInput.

0:58 TInput is going to be...I'm just going to replace all the pieces with this and I'm just returning the input. Now, whatever I pass in, I'm going to get returned to in here. I can pass in an object. I can say blah, blah, blah, blah, blah, blah, blah, and that's all going to be returned to me like this. This is a good way of thinking about the difference between function overloads and generics.

A simple function - returnWhatIPassIn - can be enough to stump many newbie TypeScript devs.

Here, I compare two approaches - function overloads and generics - to see which one works best.

Discuss on Twitter

More Tips

Assign local variables to default generic slots to dry up your code and improve performance