Function overloads in TypeScript are an incredibly powerful tool for building. things that really are not possible to build otherwise. Here we have a compose function. which takes in multiple other functions and produces another function.
This is a key tenet of functional programming.
function compose(...args, any[]) {
return {} as any;
};
So here if we just had an addOne function we would just have a number which returned another number.
function addOneToString = compose(addOne);
But what if we wanted to chain several functions together? With the result of each previous function piping into the next.
const addOneToString = compose(addOne, numToString, stringToNum)
How would we achieve this? We use function overloads.
We've got the actual implementation of the function here and you can see that it's kind of stubbed. It's just got an any inside it, which TypeScript allows you to do.
function compose(...args, any[]) {
return {} as any;
};
What's actually interesting are the overloads. So we have a function that takes in a function and returns a function.
export function compose<Input, FirstArg>(
func: (input: Input) => FirstArg
): (input: Input) => FirstArg
We have the first signature or the first overload for compose, which takes in two generics. It has the Input which is the very first thing you input into the returned function and then you have the first argument.
So here we're saying FirstArg, because further down we're going to add a SecondArg and a ThirdArg.
This is only triggered if you use one argument.
function addOneToString = compose(addOne);
If you add in a second function there then the second overload is triggered. So now you have an <Input, FirstArg, SecondArg>. And here your arguments func and func2. func returns the FirstArg, and that is the input for func2, which returns the SecondArg.
export function compose<Input, FirstArg, SecondArg>(
func: (input: Input) => FirstArg,
func2: (input: FirstArg) => SecondArg
): (input: Input) => SecondArg
And the third overload here it means it just does the same thing again but adds a third arg to it.
export function compose<Input, FirstArg, SecondArg, ThirdArg>(
func: (input: Input) => FirstArg,
func2: (input: FirstArg) => SecondArg,
func3: (input: SecondArg) => ThirdArg
): (input: Input) => ThirdArg
What this does is protect you from cases where the output from one of the previous functions doesn't match the input of the next function.
So for example you can't run numToString and then addOne because numToString returns a string and addOne takes in a number.
const addOneToString = compose(numToString, addOne)
And this means that function overloads are incredibly powerful for these sorts of compositions.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.