If you look at the code carefully you realize the meaning of a,b,c,d change based on how many arguments are passed in. Also the function only expects 1, 2 or 4 arguments. These constraints can be enforced and documented using function overloading. You just:

declare the function header multiple times,

the last function header is the one that is actually active within the function body but is not available to the outside world.

Here the first three function signatures are what is available as valid calls to padding:

padding(1); // Okay: all
padding(1,1); // Okay: topAndBottom, leftAndRight
padding(1,1,1,1); // Okay: top, right, bottom, left
padding(1,1,1); // Error: Not a part of the available overloads

Of course it's important for the final declaration (the true declaration as seen from inside the function) to be compatible with all the overloads. This is because that is the true nature of the function calls that the function body needs to account for.

Function overloading in TypeScript doesn't come with any runtime overhead. It just allows you to document the manner you expect the function to be called in and the compiler holds the rest of your code in check.