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.
More Tips
Type Predicates
1 min
TypeScript 5.1 Beta is OUT!
2 mins
How to Name your Types
4 mins
Don't use return types, unless...
4 mins
TypeScript 5.0 Beta Deep Dive
6 mins
Conform a Derived Type Without Losing Its Literal Values
1 min
Avoid unexpected behavior of React’s useState
1 min
Understand assignability in TypeScript
2 mins
Use infer in combination with string literals to manipulate keys of objects
1 min
Access deeper parts of objects and arrays
1 min
Ensure that all call sites must be given value
1 min
Understand how TypeScript infers literal types
1 min
Get a TypeScript package ready for release to NPM in under 2 minutes
1 min
Use assertion functions inside classes
1 min
Assign local variables to default generic slots to dry up your code and improve performance
2 mins
Know when to use generics
2 mins
Map over a union type
1 min
Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig
1 min
Use generics to dynamically specify the number, and type, of arguments to functions
1 min
Use 'declare global' to allow types to cross module boundaries
2 mins
Turn a module into a type
2 mins
Create autocomplete helper which allows for arbitrary values
2 mins
Use deep partials to help with mocking an entity
1 min
Throw detailed error messages for type checks
1 min
Create a 'key remover' function which can process any generic object
1 min
Use generics in React to make dynamic and flexible components
1 min
Create your own 'objectKeys' function using generics and the 'keyof' operator
1 min
Write your own 'PropsFrom' helper to extract props from any React component
1 min
Use 'extends' keyword to narrow the value of a generic
1 min
Use function overloads and generics to type a compose function
2 mins
Decode URL search params at the type level with ts-toolbelt
2 mins
Use 'in' operator to transform a union to another union
2 mins
Derive a union type from an object
2 mins